服务发现----Consul
为什么要学习consul服务发现?
因为一套微服务架构中有很多个服务需要管理,也就是说会有很多对grpc。 如果一一对应的进行管理会很繁琐所以我们需要有一个管理发现的机制
Consul的介绍
Consul是什么
Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。 Consul是分布式的、高可用 的、可横向扩展的。它具备以下特性 :
service discovery:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas 提供的也可以一样注册。
health checking:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到 故障的服务上面。
key/value storage:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。 multi-datacenter:无需复杂的配置,即可支持任意数量的区域。
下面的例子有助于我们理解服务发现的形式:
例如邮递员去某公司一栋大楼投递快件,向门卫询问员工甲在哪一个房间,门卫拿起桌上的通讯录查询,告知邮递
员员工甲在具体什么位置。假如公司来了一个员工乙,他想让邮递员送过来,就要先让门卫知道自己在哪一个房
间,需要去门卫那边登记,员工乙登记后,当邮递员向门卫询问时,门卫就可以告诉邮递员员工乙的具体位置。门
卫知道员工乙的具体位置的过程就是服务发现,员工乙的位置信息可以被看作服务信息,门卫的通讯录就是上文中
提到的数据交换格式,此例中员工乙就是上文的已方,门卫就是服务发现的提供者。
什么是服务发现
微服务的框架体系中,服务发现是不能不提的一个模块。我相信了解或者熟悉微服务的童鞋应该都知道它的重要
性。这里我只是简单的提一下,毕竟这不是我们的重点。我们看下面的一幅图片:
图中,客户端的一个接口,需要调用服务A-N。客户端必须要知道所有服务的网络位置的,以往的做法是配置是配 置文件中,或者有些配置在数据库中。这里就带出几个问题:
需要配置N个服务的网络位置,加大配置的复杂性 服务的网络位置变化,都需要改变每个调用者的配置 集群的情况下,难以做负载(反向代理的方式除外)
总结起来一句话:服务多了,配置很麻烦,问题多多
既然有这些问题,那么服务发现就是解决这些问题的。话说,怎么解决呢?我们再看一张图:
与之前一张不同的是,加了服务发现模块。图比较简单这边文字描述下。服务A-N把当前自己的网络位置注册到服务发现模块(这里注册的意思就是告诉),服务发现就以K-V的方式记录下,K一般是服务名,V就是 IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问的了(这就是健康检查)。客户端在调用服务A-N的 时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样的方式是不是就可以解决上面的问 题了呢?客户端完全不需要记录这些服务网络位置,客户端和服务端完全解耦!
Consul的安装
Consul用Golang实现,因此具有天然可移植性 (支持 Linux、windows和macOS)。安装包仅包含一个可执行文
件。 Consul安装非常简单,只需要下载对应系统的软件包并解压后就可使用。
下载安装
#这里以 Linux系统为例:
$ wget https://releases.hashicorp.com/consul/1.2.0/consul_1.2.0_linux_amd64.zip
$ unzip consul_1.2.0_linux_amd64.zip
$ mv consul /usr/local/bin/
其它系统版本可在这里下载: https://www.consul.io/downloads.html
验证安装
安装 Consul后,通过执行 consul命令,你可以看到命令列表的输出
$ consul
就证明成功了
合理的创建标题,有助于目录的生成
Consul 的角色
client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群.
server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其他数据中心通讯。 每个数据中心的 server 数量推荐为 3 个或是 5 个。
运行 Consul代理
Consul是典型的 C/S架构,可以运行服务模式或客户模式。每一个数据中心必须有至少一个服务节点, 3到5个服 务节点最好。非常不建议只运行一个服务节点,因为在节点失效的情况下数据有极大的丢失风险。
运行Agent
完成Consul的安装后,必须运行agent。 agent可以运行为server或client模式。每个数据中心至少必须拥有一台server。建议在一个集群中有3或者5个server。部署单一的server,在出现失败时会不可避免的造成数据丢失。其他的agent运行为client模式。一个client是一个非常轻量级的进程。用于注册服务,运行健康检查和转发对server的查询。agent必须在集群中的每个主机上运行。
启动 Consul Server
#node1:
$ consul agent -server -bootstrap-expect 2 -data-dir /tmp/consul -node=n1 - bind=192.168.110.123 -ui -config-dir /etc/consul.d -rejoin -join 192.168.110.123 - client 0.0.0.0
#运行cosnul agent以server模式
-server : 定义agent运行在server模式
-bootstrap-expect :在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直 等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap共用
-data-dir:提供一个目录用来存放agent的状态,所有的agent允许都需要该目录,该目录必须是稳定的,系统 重启后都继续存在
-node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
-bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0
-ui: 启动web界面
-config-dir::配置文件目录,里面所有以.json结尾的文件都会被加载
-rejoin:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。
-client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服 务,如果你要对外提供服务改成0.0.0.0
#node2:
$ consul agent -server -bootstrap-expect 2 -data-dir /tmp/consul -node=n2 -bind=192.168.110.148 -ui -rejoin -join 192.168.110.123
-server : 定义agent运行在server模式
-bootstrap-expect :在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直 等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap共用
-bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0
-node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
-ui: 启动web界面
-rejoin:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。
-config-dir::配置文件目录,里面所有以.json结尾的文件都会被加载
-client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服 务,如果你要对外提供服务改成0.0.0.0
-join 192.168.110.121 : 启动时加入这个集群
启动 Consul Client
#node3:
$ consul agent -data-dir /tmp/consul -node=n3 -bind=192.168.110.124 -config-dir /etc/consul.d -rejoin -join 192.168.110.123
运行cosnul agent以client模式,-join 加入到已有的集群中去。
查看集群成员
新开一个终端窗口运行consul members, 你可以看到Consul集群的成员:
$ consul members
停止Agent
你可以使用Ctrl-C 优雅的关闭Agent. 中断Agent之后你可以看到他离开了集群并关闭.
在退出中,Consul提醒其他集群成员,这个节点离开了.如果你强行杀掉进程.集群的其他成员应该能检测到这个节点失 效了.当一个成员离开,他的服务和检测也会从目录中移除.当一个成员失效了,他的健康状况被简单的标记为危险,但 是不会从目录中移除.Consul会自动尝试对失效的节点进行重连.允许他从某些网络条件下恢复过来.离开的节点则不 会再继续联系.
此外,如果一个agent作为一个服务器,一个优雅的离开是很重要的,可以避免引起潜在的可用性故障影响达成一致性 协议. consul优雅的退出
$ consul leave
注册服务
搭建好conusl集群后,用户或者程序就能到consul中去查询或者注册服务。可以通过提供服务定义文件或者调用
HTTP API来注册一个服务. 首先,为Consul配置创建一个目录.Consul会载入配置文件夹里的所有配置文件.在Unix系统中通常类似
/etc/consul.d (.d 后缀意思是这个路径包含了一组配置文件).
$ mkdir /etc/consul.d
然后,我们将编写服务定义配置文件.假设我们有一个名叫web的服务运行在 10000端口.另外,我们将给他设置一个标 签.这样我们可以使用他作为额外的查询方式:
{
"service":{ #服务
"name":"web", #名称
"tags":[ #标记
"master"
],
"address":"127.0.0.1", #ip
"port":10000, #端口
"checks":[
{
"http":"http://localhost:10000/health",
"interval":"10s" #检查时间
}
]
}
}
测试程序
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Println("hello Web3! This is n3或者n2")
fmt.Fprintf(w, "Hello Web3! This is n3或者n2") }
func healthHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("health check! n3或者n2")
}
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/health", healthHandler)
http.ListenAndServe(":10000", nil)
}
查询服务
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" | “Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
创建一个自定义列表
一旦agent启动并且服务同步了.我们可以通过DNS或者HTTP的API来查询服务.
DNS API
让我们首先使用DNS API来查询.在DNS API中,服务的DNS名字是 NAME.service.consul. 虽然是可配置的,但默认的 所有DNS名字会都在consul命名空间下.这个子域告诉Consul,我们在查询服务,NAME则是服务的名称.
对于我们上面注册的Web服务.它的域名是 web.service.consul :
$ dig @127.0.0.1 -p 8600 web.service.consul
有也可用使用 DNS API 来接收包含 地址和端口的 SRV记录:
$ dig @127.0.0.1 -p 8600 web.service.consul SRV