服务发现consul

image.png
每个服务建立的时候,都会注册到服务发现。服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。

有服务发现后,client、server工作流程:

  1. 每个server启动时,都将自己的IP、port 和 服务名 注册给 ”服务发现“
  2. 当 client 向服务发现发起服务请求时, “服务发现”会自动找一个可用的 服务,将其 IP/port/服务名返回给 client
  3. client 再借助服务发现,访问 server。

    服务发现的种类:

  • consul: 常应用于 go-micro 中。
  • mdns:go-micro中默认自带的服务发现。
  • etcd:k8s 内嵌的服务发现
  • zookeeper:java中较常用。

    consul 关键特性

  1. 服务发现: consul 提供服务, 服务端 主动向 consul 发起注册。
  2. 健康检查: 定时发送消息,类似于 “心跳包”,保证 客户端获得到的 一定是 健康的服务。
  3. 键值存储: consul 提供,但是我们使用 redis
  4. 多数据中心:可以轻松搭建集群。

    consul 常用命令

  • consul agent

    • -bind=0.0.0.0 指定 consul所在机器的 IP地址。 默认值:0.0.0.0
    • -http-port=8500 consul 自带一个web访问的默认端口:8500
    • -client=127.0.0.1 表明哪些机器可以访问consul 。 默认本机。0.0.0.0 所有机器均可访问。
    • -config-dir=foo 所有主动注册服务的 描述信息
    • -data-dir=path 储存所有注册过来的srv机器的详细信息。
    • -dev 开发者模式,直接以默认配置启动 consul
    • -node=hostname 服务发现的名字。
    • -rejoin consul 启动的时候,加入到的 consul集群
    • -server 以服务方式开启consul, 允许其他的consul 连接到开启的 consul上 (形成集群)。如果不加 -server, 表示以 “客户端” 的 方式开启。不能被连接。
    • -ui 可以使用 web 页面 来查看服务发现的详情

      服务发现讲义

      开发的时候,客户端的一个接口可能需要调用N个服务,客户端必须知道所有服务的网络位置(ip+port),如下图所示
      image.png
      以往的做法是把服务的地址放在配置文件和数据库中,这样就有以下几个问题:
  • 需要配置N个服务的网络位置,加大配置的复杂性

  • 服务的网络位置变化,需要改变每个调用者的配置
  • 集群的情况下,难以做负载(反向代理的方式除外)

总结起来一句话:服务多了,配置很麻烦,问题一大堆
所以现在就选择服务发现来解决这些问题。我们来看一下,服务发现如何解决这个问题,具体设计如下:
image.png
与之前解决方法不同的是,加了个服务发现模块。服务端把当前自己的网络位置注册到服务发现模块(这里注册的意思就是告诉),服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问的了(这就是健康检查)。客户端在调用服务A到N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样的方式是不是就可以解决上面的问题了呢?客户端完全不需要记录这些服务的网络位置,客户端和服务端完全解耦!
常见的服务发现框架有:Etcd、Eureka、Consul、Zookeeper
这里我们选择go-micro默认的服务发现框架consul来做一个详细介绍。

了解consul并使用

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。包含多个组件,但是作为一个整体,为你的基础设施提供服务发现和服务配置的工具.他提供以下关键特性:
服务发现:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
健康检查:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。(心跳机制)
键/值存储:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
多数据中心:无需复杂的配置,即可支持任意数量的区域。
官方建议:最好是三台或者三台以上的consul在运行,同名服务最好是三台或三台以上,默认可以搭建集群

consul安装

Consul用Golang实现,因此具有天然可移植性 (支持 Linux、windows和macOS)。安装包仅包含一个可执行文件。 Consul安装非常简单,只需要下载对应系统的软件包并解压后就可使用。
安装步骤如下:

  1. # 这里以 ubuntu系统为例:
  2. $ wget https://releases.hashicorp.com/consul/1.5.2/consul_1.5.2_linux_amd64.zip
  3. $ unzip consul_1.5.2_linux_amd64.zip
  4. $ sudo mv consul /usr/local/bin/

教室网速原因,用老师给的离线包解压即可
其他系统版本可以在这里下载:https://www.consul.io/downloads.html
安装验证:
安装 Consul后,通过执行 consul命令,你可以看到命令列表的输出,没有报错就成功了
image.png
consul安装好之后,我们来使用一下吧。首先我们来看一下consul都有哪些命令。使用命令consul -h可以查看consul支持的所有参数,而且每个参数里面还支持其他参数,下面我们来具体看看。
agent:指令是consul的核心,它运行agent来维护成员的重要信息、运行检查、服务宣布、查询处理等等。

  1. ==> Usage: consul agent [options]
  2. Starts the Consul agent and runs until an interrupt is received. The
  3. agent represents a single node in a cluster.
  4. Options:
  5. -advertise=addr Sets the advertise address to use
  6. -advertise-wan=addr Sets address to advertise on wan instead of
  7. advertise addr
  8. -bootstrap Sets server to bootstrap mode
  9. -bind=0.0.0.0 Sets the bind address for cluster
  10. communication
  11. -http-port=8500 Sets the HTTP API port to listen on
  12. -bootstrap-expect=0 Sets server to expect bootstrap mode.
  13. -client=127.0.0.1 Sets the address to bind for client access.
  14. This includes RPC, DNS, HTTP and HTTPS (if
  15. configured)
  16. -config-file=foo Path to a JSON file to read configuration
  17. from. This can be specified multiple times.
  18. -config-dir=foo Path to a directory to read configuration
  19. files from. This will read every file ending
  20. in ".json" as configuration in this
  21. directory in alphabetical order. This can be
  22. specified multiple times.
  23. -data-dir=path Path to a data directory to store agent
  24. state
  25. -dev Starts the agent in development mode.
  26. -recursor=1.2.3.4 Address of an upstream DNS server.
  27. Can be specified multiple times.
  28. -dc=east-aws Datacenter of the agent (deprecated: use
  29. 'datacenter' instead).
  30. -datacenter=east-aws Datacenter of the agent.
  31. -encrypt=key Provides the gossip encryption key
  32. -join=1.2.3.4 Address of an agent to join at start time.
  33. Can be specified multiple times.
  34. -join-wan=1.2.3.4 Address of an agent to join -wan at start
  35. time. Can be specified multiple times.
  36. -retry-join=1.2.3.4 Address of an agent to join at start time
  37. with retries enabled. Can be specified
  38. multiple times.
  39. -retry-interval=30s Time to wait between join attempts.
  40. -retry-max=0 Maximum number of join attempts. Defaults to
  41. 0, which will retry indefinitely.
  42. -retry-join-ec2-region EC2 Region to use for discovering servers to
  43. join.
  44. -retry-join-ec2-tag-key EC2 tag key to filter on for server
  45. discovery
  46. -retry-join-ec2-tag-value EC2 tag value to filter on for server
  47. discovery
  48. -retry-join-gce-project-name Google Compute Engine project to discover
  49. servers in
  50. -retry-join-gce-zone-pattern Google Compute Engine region or zone to
  51. discover servers in (regex pattern)
  52. -retry-join-gce-tag-value Google Compute Engine tag value to filter
  53. for server discovery
  54. -retry-join-gce-credentials-file Path to credentials JSON file to use with
  55. Google Compute Engine
  56. -retry-join-wan=1.2.3.4 Address of an agent to join -wan at start
  57. time with retries enabled. Can be specified
  58. multiple times.
  59. -retry-interval-wan=30s Time to wait between join -wan attempts.
  60. -retry-max-wan=0 Maximum number of join -wan attempts.
  61. Defaults to 0, which will retry
  62. indefinitely.
  63. -log-level=info Log level of the agent.
  64. -node=hostname Name of this node. Must be unique in the
  65. cluster
  66. -node-meta=key:value An arbitrary metadata key/value pair for
  67. this node.
  68. This can be specified multiple times.
  69. -protocol=N Sets the protocol version. Defaults to
  70. latest.
  71. -rejoin Ignores a previous leave and attempts to
  72. rejoin the cluster.
  73. -server Switches agent to server mode.
  74. -syslog Enables logging to syslog
  75. -ui Enables the built-in static web UI server
  76. -ui-dir=path Path to directory containing the Web UI
  77. resources
  78. -pid-file=path Path to file to store agent PID

info:指令提供了各种操作时可以用到的debug信息,对于client和server,info有返回不同的子系统信息,目前有以下几个KV信息:agent(提供agent信息),consul(提供consul库的信息),raft(提供raft库的信息),serf_lan(提供LAN gossip pool),serf_wan(提供WAN gossip pool)
leave:指令触发一个优雅的离开动作并关闭agent,节点离开后不会尝试重新加入集群中。运行在server状态的节点,节点会被优雅的删除,这是很严重的,在某些情况下一个不优雅的离开会影响到集群的可用性。
members:指令输出consul agent目前所知道的所有的成员以及它们的状态,节点的状态只有alive、left、failed三种状态。
-detailed:输出每个节点更详细的信息。-rpc-addr:一个rpc地址,agent可以链接上来发送命令,如果没有指定,默认是127.0.0.1:8400。-status:过滤出符合正则规则的节点
reload:指令可以重新加载agent的配置文件。SIGHUP指令在重新加载配置文件时使用,任何重新加载的错误都会写在agent的log文件中,并不会打印到屏幕。

consul简单使用

首先我们要运行consul,运行有两种模式,分别是==server==和==client==,通过下面的命令开启:

  1. consul agent -server
  2. consul agent

每个数据中心至少必须拥有一个server。一个client是一个非常轻量级的进程.用于注册服务,运行健康检查和转发对server的查询.agent必须在集群中的每个主机上运行.

server模式启动

一个consul:

  1. $ consul agent(代理) -server(以server模式启动) -bootstrap-expect(分布式集群1个) 1
  2. -data-dir(指定目录位置) /tmp/consul -node=n1(当前节点名称叫n1
  3. -bind=192.168.6.108(指定 consul所在机器的 IP地址) -ui(可以使用 web 页面 来查看服务发现的详情)
  4. -rejoin consul 启动的时候,加入到的 consul集群)
  5. -config-dir=/etc/consul.d/ (所有主动注册服务的描述信息)
  6. -client 0.0.0.0(表明哪些机器可以访问consul 默认本机。0.0.0.0 所有机器均可访问。)

image.png
需要先在/etc/下面创建consul.d目录

  • -server : 定义agent运行在server模式
  • -bootstrap-expect :在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap共用
  • -bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0
  • -node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
  • -ui: 启动web界面 :8500
  • -rejoin:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。
  • -config-dir:配置文件目录,里面所有以.json结尾的文件都会被加载
  • -client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
  • data-dir:提供一个目录用来存放agent的状态,所有的agent允许都需要该目录,该目录必须是稳定的,系统重启后都继续存在

    client模式启动

    1. $ consul agent -data-dir /tmp/consul -node=n2 -bind=192.168.137.82 -config-dir /etc/consul.d -rejoin -join 192.168.137.81
    运行cosnul agent以client模式,-join 加入到已有的集群中去。

    查看consul成员

    image.png

    停止agent

    你可以使用Ctrl-C 关闭Agent. 中断Agent之后你可以看到他离开了集群并关闭.
    在退出中,Consul提醒其他集群成员,这个节点离开了.如果你强行杀掉进程.集群的其他成员应该能检测到这个节点失效了.当一个成员离开,他的服务和检测也会从目录中移除.当一个成员失效了,他的健康状况被简单的标记为危险,但是不会从目录中移除.Consul会自动尝试对失效的节点进行重连.允许他从某些网络条件下恢复过来.离开的节点则不会再继续联系.
    此外,如果一个agent作为一个服务器,一个优雅的离开是很重要的,可以避免引起潜在的可用性故障影响达成一致性协议.consul优雅的退出:
    $ consul leave

    注册服务

    搭建好conusl集群后,用户或者程序就能到consul中去查询或者注册服务。可以通过提供服务定义文件或者调用HTTP API来注册一个服务
    步骤:
  1. 进入配置文件路径 cd /etc/consul.d/
  2. 创建 json 文件。 sudo vim web.json
  3. 按 json 的语法,填写 服务信息。

image.png

  1. 重新启动 consul

    1. consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.6.108 -ui -rejoin -config-dir=/etc/consul.d/ -client 0.0.0.0
  2. 查询 服务

image.png

健康检查

健康检查是服务发现的关键组件.预防使用到不健康的服务.和服务注册类似,一个检查可以通过检查定义或HTTP API请求来注册.我们将使用和检查定义来注册检查.和服务类似,因为这是建立检查最常用的方式

  1. sudo vim /etc/consul.d/web.json 打开配置文件
  2. 写入 服务的配置 信息。

image.png

  1. 执行命令,consul reload。 或者,关闭consul 再重启。
  2. 使用 浏览器 键入 192.168.6.108:8500 查看 “bj38” 这个服务 的 健康状况
    • 不健康!没有服务bj38 给 consul 实时回复!
  3. 除了 http 实现健康检查外,还可以使用 “脚本”、“tcp”、“ttl” 方式进行健康检查。

在/etc/consul.d/目录下面创建文件web2.json,内容如下:

  1. {"service": {
  2. "name": "web",
  3. "tags": ["extract", "verify", "compare", "idcard"],
  4. "address": "192.168.137.130",
  5. "port": 9000,
  6. "check": {
  7. "id": "api",//这个名字无所谓,后面调用
  8. "name": "HTTP API on port 9000",//健康检查的名字
  9. "http": "http://localhost:9000",//主机ip
  10. "interval": "10s",//心跳包发送时常,就是多久发一次心跳包
  11. "timeout": "1s"//超过这个时间就认为是不健康的
  12. }
  13. }
  14. }

这时候我们没有开启这个服务,所以这个时候健康检查会出错。打开web界面,如下
consul做健康检查的必须是Script、HTTP、TCP、TTL中的一种。
Script类型需要提供Script脚本和interval变量。具体配置如下:

  1. {
  2. "check": {
  3. "id": "mem-util",
  4. "name": "Memory utilization",
  5. "script": "/usr/local/bin/check_mem.py",
  6. "interval": "10s",
  7. "timeout": "1s"
  8. }
  9. }

通过执行外部应用进行健康检查:这种外部程序具有退出代码,并可能产生一些输出;脚本按照指预置时间间隔来调用(比如,每30秒调用一次),类似于Nagios插件系统,脚本输出限制在4K以内,输出大于4K将截断。默认情况下,脚本超时时间为30秒——可通过timeout来配置。
HTTP类型必须提供http和Interval字段。具体代码如下:

  1. {
  2. "check": {
  3. "id": "api",
  4. "name": "HTTP API on port 5000",
  5. "http": "http://localhost:5000/health",
  6. "interval": "10s",
  7. "timeout": "1s"
  8. }
  9. }

这种检查将按照预设的时间间隔创建一个HTTP “get”请求。HTTP响应代码来标示服务所处状态:任何2xx代码视为正常,429表示警告——有很多请求;其他值表示失败。
这种类型的检查应使用curl或外部程序来处理HTTP操作。默认情况下,HTTP Checks中,请求超时时间等于调用请求的间隔时间,最大10秒。有可能使用客制的HTTP check,可以自由配置timeout时间,输出限制在4K以内,输出大于4K将截断。
TCP类型需要提供tcp和Interval字段。具体代码如下:

  1. {
  2. "check": {
  3. "id": "ssh",
  4. "name": "SSH TCP on port 22",
  5. "tcp": "localhost:22",
  6. "interval": "10s",
  7. "timeout": "1s"
  8. }
  9. }

这种检查将按照预设的时间间隔与指定的IP/Hostname和端口创建一个TCP连接。服务的状态依赖于TCP连接是否成功——如果连接成功,则状态是“success”;否则状态是“critical”。如果一个Hostname解析为一个IPv4和一个IPv6,将尝试连接这两个地址,第一次连接成功则服务状态是“success”。默认情况下,TCP checks中,请求超时时间等于调用请求的间隔时间,最大10秒。也是可以自由配置的。
TTL(Timeto Live生存时间)类型只需提供ttl,具体配置如下:

  1. {
  2. "check": {
  3. "id": "web-app",
  4. "name": "Web App Status",
  5. "notes": "Web app does a curl internally every 10 seconds",
  6. "ttl": "30s"
  7. }
  8. }

这种checks为给定TTL保留了最后一种状态,checks的状态必须通过HTTP接口周期性更新,如果外部接口没有更新状态,那么状态就会被认定为不正常。 TTL checks同时会将其最后已知状态更新至磁盘,这允许Agent通过重启后恢复到已知的状态。通过TTL端上一次check来维持健康状态的有效性。
我们也可以通过页面来查看,在浏览器输入网址:http://192.68.130.137:8500
下面这里这个服务没启动,所以不健康。
image.png

consul和grpc结合使用

安装 consul 源码包:
$ go get -u -v github.com/hashicorp/consul

使用整体流程

  1. 创建 proto文件, 指定 rpc 服务
  2. 启动 consul 服务发现(consul agent -dev)
  3. 启动server
    1. 获取consul 对象。
    2. 使用 consul对象,将 server 信息,注册给 consul
    3. 启动服务
  4. 启动client
    1. 获取consul 对象。
    2. 使用consul对象,从consul 上获取健康的 服务。
    3. 再访问服务 (grpc远程调用)

      编码实现:

      用到的函数: ```go // 从consul 服务发送上获取 健康服务 func (h Health) Service(service, tag string, passingOnly bool, q QueryOptions) ([]ServiceEntry, QueryMeta, error)

// 参数: service: 服务名。 — 注册服务时,指定该string tag:外名/别名。 如果有多个, 任选一个 passingOnly:是否通过健康检查。 true q:查询参数。 通常传 nil // 返回值: ServiceEntry: 存储服务的切片。 QueryMeta:额外查询返回值。 nil error: 错误信息

  1. proto文件
  2. ```go
  3. syntax = "proto3";
  4. package pb;
  5. message Person {
  6. string name = 1;
  7. int32 age = 2;
  8. }
  9. // 添加 rpc服务
  10. service hello {
  11. rpc sayHello (Person) returns (Person);
  12. }

服务端

  1. package main
  2. import (
  3. "google.golang.org/grpc"
  4. "day02/pb"
  5. "context"
  6. "net"
  7. "fmt"
  8. "github.com/hashicorp/consul/api"
  9. )
  10. // 定义类
  11. type Children struct {
  12. }
  13. // 绑定类方法, 实现借口
  14. func (this *Children)SayHello(ctx context.Context, p *pb.Person) (*pb.Person, error) {
  15. p.Name = "hello " + p.Name
  16. return p, nil
  17. }
  18. func main() {
  19. // 把grpc服务,注册到consul上.
  20. // 1. 初始化consul 配置
  21. consulConfig := api.DefaultConfig()//这个api是github上的一个包
  22. // 2. 创建 consul 对象
  23. consulClient, err := api.NewClient(consulConfig)
  24. if err != nil {
  25. fmt.Println("api.NewClient err:", err)
  26. return
  27. }
  28. // 3. 告诉consul, 即将注册的服务的配置信息
  29. reg := api.AgentServiceRegistration {
  30. ID:"bj38",
  31. Tags:[]string{"grcp", "consul"},
  32. Name:"grpc And Consul",
  33. Address:"127.0.0.1",
  34. Port:8800,
  35. Check:&api.AgentServiceCheck{
  36. CheckID:"consul grpc test",
  37. TCP:"127.0.0.1:8800",
  38. Timeout:"1s",
  39. Interval:"5s",
  40. },
  41. }
  42. // 4. 注册 grpc 服务到 consul 上
  43. consulClient.Agent().ServiceRegister(&reg)
  44. //////////////////////以下为 grpc 服务远程调用////////////////////////
  45. // 1.初始化 grpc 对象,
  46. grpcServer := grpc.NewServer()
  47. // 2.注册服务
  48. pb.RegisterHelloServer(grpcServer, new(Children))
  49. // 3.设置监听, 指定 IP/port
  50. listener, err := net.Listen("tcp", "127.0.0.1:8800")
  51. if err != nil {
  52. fmt.Println("Listen err:", err)
  53. return
  54. }
  55. defer listener.Close()
  56. fmt.Println("服务启动... ")
  57. // 4. 启动服务
  58. grpcServer.Serve(listener)
  59. }

客户端

  1. package main
  2. import (
  3. "google.golang.org/grpc"
  4. "day02/pb"
  5. "context"
  6. "fmt"
  7. "github.com/hashicorp/consul/api"
  8. "strconv"
  9. )
  10. func main() {
  11. // 初始化 consul 配置
  12. consulConfig := api.DefaultConfig()
  13. // 创建consul对象 -- (可以重新指定 consul 属性: IP/Port , 也可以使用默认)
  14. consulClient, err := api.NewClient(consulConfig)
  15. // 服务发现. 从consuL上, 获取健康的服务
  16. services, _, err := consulClient.Health().Service("grpc And Consul", "grcp", true, nil)
  17. // 简单的负载均衡.
  18. addr := services[0].Service.Address + ":" + strconv.Itoa(services[0].Service.Port)
  19. //////////////////////以下为 grpc 服务远程调用///////////////////////////
  20. // 1. 链接服务
  21. //grpcConn, _ := grpc.Dial("127.0.0.1:8800", grpc.WithInsecure())
  22. // 使用 服务发现consul 上的 IP/port 来与服务建立链接
  23. grpcConn, _ := grpc.Dial(addr, grpc.WithInsecure())
  24. // 2. 初始化 grpc 客户端
  25. grpcClient := pb.NewHelloClient(grpcConn)
  26. var person pb.Person
  27. person.Name = "Andy"
  28. person.Age = 18
  29. // 3. 调用远程函数
  30. p, err := grpcClient.SayHello(context.TODO(), &person)
  31. fmt.Println(p, err)
  32. }

服务注销

  1. package main
  2. import "github.com/hashicorp/consul/api"
  3. func main() {
  4. // 1. 初始化 consul 配置
  5. consuConfig := api.DefaultConfig()
  6. // 2. 创建 consul 对象
  7. consulClient, _ := api.NewClient(consuConfig)
  8. // 3. 注销服务
  9. consulClient.Agent().ServiceDeregister("bj38")
  10. }

学完了consul命令行的使用,接着我们来看一下,在代码中如何通过,这里我们用grpc和consul结合使用。
我们操作consul使用的是github.com/hashicorp/consul/包,我们先来下载一下,命令如下:
$ go get -u -v github.com/hashicorp/consul
然后我们先注册一个服务到consul上:

把grpc服务注册到consul上

代码如下:

  1. func main(){
  2. //初始化consul配置
  3. consulConfig := api.DefaultConfig()
  4. //获取consul操作对象
  5. registry,_ := api.NewClient(consulConfig)
  6. //注册服务,服务的常规配置
  7. registerService := api.AgentServiceRegistration{
  8. ID:"1",
  9. Tags:[]string{"testHello"},
  10. Name:"HelloService",
  11. Port:8080,
  12. Address:"192.168.137.130",
  13. Check:&api.AgentServiceCheck{
  14. TCP:"192.168.137.130:8080",
  15. Timeout:"5s",
  16. Interval:"5s",
  17. },
  18. }
  19. //注册服务到consul上
  20. registry.Agent().ServiceRegister(&registerService)
  21. //获取grpc服务端对象
  22. grpcServer := grpc.NewServer()
  23. //注册grpc服务
  24. pb.RegisterHelloServiceServer(grpcServer,new(HelloService))
  25. //设置服务端监听
  26. lis,err := net.Listen("tcp",":1234")
  27. if err != nil {
  28. panic(err)
  29. }
  30. //在指定端口上提供grpc服务
  31. grpcServer.Serve(lis)
  32. }

服务发现

  1. func main(){
  2. //初始化consul配置, 客户端服务器需要一致
  3. consulConfig := api.DefaultConfig()
  4. //获取consul操作对象
  5. registerClient,_ := api.NewClient(consulConfig)
  6. //获取地址
  7. serviceEntry,_,_ :=registerClient.Health().Service("HelloService","testHello",false,&api.QueryOptions{})
  8. //和grpc服务建立连接
  9. conn,err := grpc.Dial(serviceEntry[0].Service.Address+":"+strconv.Itoa(serviceEntry[0].Service.Port),grpc.WithInsecure())
  10. if err != nil {
  11. panic(err)
  12. }
  13. defer conn.Close()
  14. client := pb.NewHelloServiceClient(conn)
  15. reply, err := client.Hello(context.Background(),&pb.Person{Name:"lisi",Age:100})
  16. if err != nil {
  17. panic(err)
  18. }
  19. fmt.Println("reply,",reply)
  20. }

注销服务

  1. func main(){
  2. //初始化consul配置,客户端服务器需要一致
  3. consulConfig := api.DefaultConfig()
  4. //获取consul操作对象
  5. registerClient,_ := api.NewClient(consulConfig)
  6. //注销服务
  7. client.Agent().ServiceDeregister("1")
  8. }

image.png

好处

没有服务发现,客户端需要访问固定ip的服务,当服务ip地址发生变化则访问不到,需要更改ip。而服务发现只需要查询相应服务名即可,而且不需要记下来各个服务的ip地址。