Consul 随记
consul 包含多个组件,但是作为一个整体对外提供服务发现和服务配置工具:
提供的关键特性有:
服务发现:发现的是服务对应的IP地址和PORT端口号
健康检查:检查服务节点状态
Key/Value存储 :提供动态配置(简易配置文件或者键值对数据库)
多数据中心:开箱支持分布式
Consul Agent Server( 每个数据中心建议3-5台Server集群 )
基础设施中需要发现其他服务的组件:可以查询 Consul agent 或者 server
Consul集群的每个节点都必须先安装Consul :
例如:192.168.10.10 192.168.10.11 192.168.10.12 192.168.10.13 192.168.10.14 五台主机组合成一个 Consul集群,则 每个IP地址对应的服务器节点 都必须安装 Consul. 这五台主机中至少有一台agent 运行 server 模式,其他agent运行 client 模式
运行Agent (必须在集群的每一个主机上运行Agent):运行模式有两种server 和 client
consul members: 命令可以查看Consul 集群成员(节点)
localhost:8500/v1/catalog/nodes => HTTP API(将自动转发)到Consul Server 查询集群成员 [ DNS也可以用来查询节点 ]
当一个成员离开时,他的服务与检测也会从目录中移除,成员失效,他的健康状态标记为危险,但不会被移除列表,后期会尝试重连接恢复,离开的节点不会再联系。
注册一个服务并查询服务:
可以通过提供服务定义或者调用HTTP API来注册一个服务.服务定义文件是注册服务的最通用的方式.
创建服务配置文件目录及文件
echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' \ >/etc/consul.d/web.json
$ consul agent -dev -config-dir /etc/consul.d ==> Starting Consul agent... ... [INFO] agent: Synced service 'web' ...
重启Consul 即可载入服务定义并 成功注册到服务目录
多个服务只需要:创建多个服务定义文件
查询服务:
可以通过DNS或者HTTP的API来查询服务
在DNS API中,服务的DNS名字是 NAME.service.consul
NAME 是我们的服务名称:上例为 web
dig @127.0.0.1 -p 8600 web.service.consul dig @127.0.0.1 -p 8600 web.service.consul SRV
会返回 web 这个服务运行的节点 hdp2.node.dc1.consul 和端口号,以及节点的A记录
TAGS.NAME.service.consul 可以通过DNS TAG来过滤服务
dig @127.0.0.1 -p 8600 rails.web.service.consul SRV
查询所有服务: http://localhost:8500/v1/catalog/services 查询 web服务 http://localhost:8500/v1/catalog/service/web 条件查询web服务 http://localhost:8500/v1/catalog/service/web?passing 以上服务均可以用配置文件的方式或者HTTP API 做服务更新(可保持服务不关闭)
建立服务集群:
当一个节点agent启动时,他是一个成员的孤立集群.为了了解其他集群成员这个agent必须加入一个已经存在的集群.要加入一个已经存在的集群,只需要知道一个已经存在的集群成员.通过与这个成员的沟通来发现其他成员,Consul agent可以加入任何agent而不只是处于server模式的agent。
启动另外的4台服务器节点:192.168.10.11 192.168.10.12 192.168.10.13 192.168.10.14 安装agent并启动
我们可以使用 cnsul agent -dev 参数来快速启动一个开发模式的server 但是这并不能在集群环境中使用,我们用 集群环境配置来替换 -dev参数。
每个集群中的节点(如服务器:192.168.10.11)都必须要一个唯一的名字.Consul默认会使用机器的hostname.我们可以使用-node
手动覆盖他
使用-bind指定一个绑定的地址让Consul在这个地址上进行监听,这个地址必须可以被其他集群成员访问到.绑定地址不是必须提供
-server 参数 将使节点 扮演集群的唯一server
config-dir
/etc/consul.d
选项,指定服务和健康检查定义文件存放的路径
至此:有了两个运行了Consul 的Agent, 一个是server,一个是client
这两个agent还互相不知道对方,只是作为独立的单节点集群.为了验证这个你可以在每个agent运行consul member
,只能看到各自自己这一个集群成员.
加入集群:
consul join 192。168.10.10 // 两个agent 下 运行 consul members 均可以看到来个成员节点。
自动加入集群设置:-atlas-join
选项
DNS API中节点名称结构为 NAME.node.consul
或者NAME.node.DATACENTER.consul
.如果数据中心名字省略,Consul只会查询本地数据中心.
dig @127.0.0.1 -p 8600 hdp3.node.consul
服务注册:
http://127.0.0.1:8500/v1/catalog/register
{
"Datacenter": "dc1", // 数据中心
"ID": "40e4a748-2192-161a-0510-9bf59fe950b5", // 服务唯一ID
"Node": "foobar", // 节点名称
"Address": "192.168.10.10", // 节点IP
"TaggedAddresses": { // 网络地址
"lan": "192.168.10.10",
"wan": "10.0.10.10"
},
"NodeMeta": { // 节点标记
"somekey": "somevalue"
},
"Service": {
"ID": "redis1", // 服务唯一ID
"Service": "redis", // 服务名称
"Tags": [ // 服务名相同时,服务标签
"primary",
"v1"
],
"Address": "127.0.0.1", // 服务发现地址
"Meta": {
"redis_version": "4.0" // 版本
},
"Port": 8000 // 服务发现端口
},
"Check": { // 健康检查
"Node": "foobar", // 待检查的节点
"CheckID": "service:redis1", // 待检查的服务ID
"Name": "Redis health check", // 检查名称
"Notes": "Script based health check", // 检查标记
"Status": "passing", // 健康检查状态
"ServiceID": "redis1", // 待检查服务ID
"Definition": { // 检查详细度
"TCP": "localhost:8888",
"Interval": "5s",
"Timeout": "1s",
"DeregisterCriticalServiceAfter": "30s" // 如果健康检查不通过 30s 后服务下线
}
},
"SkipNodeUpdate": false // 忽略节点更新?
}
查询服务详细信息:
http://127.0.0.1:8500/v1/catalog/service/${serviceName}
示例:
http://127.0.0.1:8500/v1/catalog/service/Golang
查询所有的服务:
http://127.0.0.1:8500/v1/catalog/services
示例:
http://127.0.0.1:8500/v1/catalog/services
查询节点名称详细信息:
http://127.0.0.1:8500/v1/catalog/node/${nodeName}
示例:
http://127.0.0.1:8500/v1/catalog/node/Golang
同一Node节点可以注册多个服务
健康检查:
添加健康检查到节点和服务.健康检查是服务发现的关键组件.预防使用到不健康的服务
和服务类似,一个检查可以通过检查定义或HTTP API请求来注册
echo '{"check": {"name": "ping", "script": "ping -c1 163.com >/dev/null", "interval": "30s"}}' \ >/etc/consul.d/ping.json
通过HTTP形式来查询节点健康状态
http://localhost:8500/v1/health/state/critical
我们可以尝试用DNS查询web服务,Consul将不会返回结果.因为服务不健康
dig @127.0.0.1 -p 8600 web.service.consul
键值数据存储:
Consul 提供的易用键值存储功能:用来保持动态配置,协助服务协调,领袖选举,做开发者可以想到的任何事情
// 检查 是否存储有key?recurse
参数可以获取多个key值 curl -v http://localhost:8500/v1/kv/?recurse
// put key值
curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key1
curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key2?flags=42
// 获取单个key值
curl http://localhost:8500/v1/kv/web/key1
// 删除用delete方法
设置自托管的UI服务
consul agent -ui
查询leader领导者:
返回的是领导者节点IP
http://172.17.0.4:8500/v1/status/leader
端口:
8300:consul agent服务relplaction、rpc(client-server)
8301:lan gossip
8302:wan gossip
8500:http api端口
8600:DNS服务端口
注册中心:每个服务提供者向注册中心登记自己提供的服务,将服务名与主机IP、端口等一些附加信息告知服务中心,注册中心按服务名分类组织服务清单。如A服务运行在192.168.1.82:3000,192.168.1.83:3000实例上。那么维护的内容如下:
服务 | 实例 |
A服务 | 192.168.99.10:3000 192.168.99.11:300 |
同时注册中心也会还会以心跳的方式去检查服务是否可用,如果不可用,则从服务实例中剔除。
服务消费者:在微服务的治理框架,服务之间的调用不再通过具体实例地址访问,而是向服务名发起调用实现。如上述例子,在注册中心注册A服务后,访问A服务的的调用方法就变为http://A服务/xxxx(代码层面是通过服务名调用服务,而不是域名!->解决了我很大的一个疑惑)
,通过以下的步骤,在真正发起请求时,把A服务替换为服务实例地址。
1. 服务消费者从服务消费者从订阅注册中心获取A服务所有实例地址;
2. 根据获取的实例地址通过负载均衡(后续有时间会写文章详细说明)的策略获取合适的Ip地址与端口,假设获取到的实例地址为:192.168.1.82:3000;
3. 把A服务地址替换为192.168.1.82:3000。
核心功能已介绍完成,下面我们就开始构建我们的注册中心。
consul相关概念
Agent
- Agent 是一个守护进程
- 运行在Consul集群的每个成员上
- 有Client 和 Server 两种模式
- 所有Agent都可以被调用DNS或者HTTP API,并负责检查和维护同步
Client
- Client 将所有RPC请求转发至Server
- Client 是相对无状态的
- Client 唯一做的就是参与LAN Gossip Pool
- Client 只消耗少量的资源和少量的网络带宽
Server
- 参与 Raft quorum(一致性判断)
- 响应RPC查询请求
- 维护集群的状态
- 转发查询到Leader 或 远程数据中心
Datacenter数据中心
- 私有的
- 低延迟
- 高带宽
Gossip
一种协议: 用来保证 最终一致性 , 即: 无法保证在某个时刻, 所有节点状态一致, 但可以保证”最终”一致
RPC(即Remote Procedure Call,远程过程调用)