在上一节中,展示了如何安装consul,本文,我们将继续深入的探究consul。
本文将:
我们将常用命令放到本文中来对照:
consul agent ##代理
-bind=0.0.0.0 ## 指定consul所在机器的IP地址,默认是0.0.0.0
-http-port=8500 ## consul自带一个web访问的默认端口
-client=127.0.0.1 ## 表明哪些机器可以访问consul,默认本机,0.0.0.0表示所有机器均可访问
-config-dir=foo ## 所有主动注册服务的描述信息
-data-dir=path ## 储存所有注册过来的server机器的详细信息
-dev ## 开发者模式,直接以默认的配置启动consul
-node=hostname ## 服务发现的名字(节点名称)
-rejion ## consul启动的时候,加入到consul的集群
-server ## 以服务方式开启consul,运行其他的consul连接到开启的consul上(形成了集群)。如果不加-server,表示以“客户端”的方式开启,不能被连 接。
-ui ## 可以使用web页面来查看服务发现的详情
比如,启动一个consul server,可以使用如下命令:
consul agent -server -bootstrap-expect=1 -data-dir=/tmp/consul -node=consulServer_1 -ui -config-dir=/etc/consul.d/ -client 0.0.0.0
说明:
-server
,以服务方式开启consul
;不加这个的话,就是以客户端
的形式启动,不具备服务端
的一些特性,如持久化保存节点数据等bootstrap-expect
:集群要求的最少server数量,当低于这个数量,集群即失效。-data-dir
,将所有注册过来的server机器的详细信息存储在/tmp/consul
目录consulServer_1
-ui
,可以使用web页面来查看服务发现的详情-config-dir
,在/etc/consul.d/
文件夹下,以json
文件形式写服务配置,主动注册服务-client
,所有机器都可用访问这个consul
启动完成后,即可连接consul,使用服务发现等功能。
接下来,我们先讲解一下Consul的基本架构,便于我们的使用。
如下图所示,是Consul 的架构:
在每个数据中心内,consul
混合了客户端(client)和服务器(server)。
其中,预计将有三到五台服务器。 这会在故障情况下的可用性与性能之间取得平衡,因为随着添加更多计算机,共识会逐渐变慢。 但是,客户端的数量没有限制,他们可以轻松扩展到成千上万。
每个数据中心中的服务器都是单个Raft对等集的一部分。 这意味着他们将共同选举一个领导者,一个具有额外职责的选定服务器。 负责人负责处理所有查询和交易。 作为共识协议的一部分,还必须将事务复制到所有对等方。 由于此要求,当非领导服务器(follower)收到RPC请求时,它将转发给集群领导。
Agent
:是在 Consul 集群的每个成员上长期运行的守护进程,通过命令 consul agent 启动运行。由于所有节点都必须运行一个 Agent,因此 Agent 可以分为 client 或 Server。
Client
:是将所有RPC转发到 Server 的 Agent。Client 是相对无状态的,Client 唯一执行的后台活动是加入 LAN gossip 池。这只有最小的资源开销,且只消耗少量的网络带宽
Server
:是一个有一组扩展功能的 Agent,这些功能包括参与 Raft 选举、维护集群状态、响应RPC查询、与其他数据中心交互 WAN gossip 和转发查询给 leader 或远程的数据中心
Consensus
:一致性。Consul 使用 Consensus 协议(具体由 Raft 算法实现)来提供一致性(由 CAP 定义),表明 leader 选举和事务的顺序达成一致
Gossip:Consul
: 使用 Gossip 协议来管理成员资格并向集群广播消息。Serf 提供了完整的 Gossip 协议,可用于多种目的,而 Consul 建立在 Serf 之上。
LAN Gossip
:指包含所有位于同一局域网或数据中心的节点的 LAN gossip 池
WAN Gossip
:指仅包含 Server 的 WAN gossip 池。这些 Server 主要分布在不同的数据中心,通常通过Internet或者广域网进行通信
RPC
:远程过程调用。一种 请求/响应 机制,允许 Client 向 Server 发起请求
更多概念,可以参考官网文档:https://www.consul.io/docs
这里有两个问题,解答一下:
不使用client客户端行不行?即,只使用Consul的Server模式
答:可以。上面的简单示例就是可以运行的,也就是说,只有Server端,当需要用到服务发现时,直接连接Server端即可。
接着问,既然可以,那为什么还需要Client端呢?
答:因为Consul Server数量不是越多越好,需要考虑压力承载(扩展性)问题。此外,Server很少有一个Server下会注册很多微服务,当Server挂掉,这个Server节点下注册的微服务都会视为无效。
基于上述问题,我们在架构中加入Consul Client模式,Client因为加入了LAN gossip
协议组成网络中(高速局域网),可以识别故障的Server节点并找到可用的Server节点继续工作。
其实Server模式负责的是用WAN gossip
协议组成的网络进行跨广域网的数据同步(多个数据中心),这点Client模式是做不到的,Client模式也提供服务的注册和查询,但Client模式不存储节点数据,Client将请求转发给Server进行处理,节点注册数据在Server端是持久化保存的。
注意,一般情况下,Server的数量是受控制的,而Client的数量可以无限多。
总之:Client模式+LAN gossip协议组成了一个数据中心中的各个节点,Server负责投票选出Leader进行数据中心内的数据同步,这个Leader还负责利用WAN gossip协议跨广域网的与其他数据中心进行数据同步。
PS:在Client注册的服务心跳监控检查由Client负责。
如下图所示,展示了服务D是如何通过consul发现服务B的:
docker拉取镜像:
root@cchui-virtual-machine:~# docker pull consul
Using default tag: latest
latest: Pulling from library/consul
339de151aab4: Pull complete
479a746f994b: Pull complete
73e6c1395cf2: Pull complete
5ceaa195774c: Pull complete
67ff69bc8fb8: Pull complete
4c9b2ffb3112: Pull complete
Digest: sha256:0dc30c8081ea3cb4a90c908a571cb4aa469ae9e3d2b27d9fb713031127360e42
Status: Downloaded newer image for consul:latest
docker.io/library/consul:latest
启动3个
Server
和 3个Client
之后,这 6 个docker服务组建一个集群。
启动节点A
docker run -it -p 8500:8500 --name=ConsulServer-1 consul agent -server -ui -node=Server-A -bootstrap-expect=3 -client=0.0.0.0
说明:
-it
: 交互形式
-p 8500:8500
:映射8500的端口
--name=ConsulServer-1
:docker名称
consul
为需要启动的镜像,后面的,属于consul的启动命令:
consul agent -server -ui -node=Server-A -bootstrap-expect=3 -client=0.0.0.0
# -server: 作为服务端启动
# -ui:可以使用web页面来查看服务发现的详情
# -node=Server-A: 节点名称为Server-A
# -bootstrap-expect=3:集群要求的最少server数量为3
# -client=0.0.0.0:所有机器均可访问
启动成功后,出现:
oot@cchui-virtual-machine:~# docker run -it -p 8500:8500 --name=ConsulServer-1 consul agent -server -ui -node=Server-A -bootstrap-expect=3 -client=0.0.0.0
==> Starting Consul agent...
Version: '1.9.5'
Node ID: 'e638fc87-fbfd-5ea2-d37a-100e1dfd2748'
Node name: 'Server-A'
Datacenter: 'dc1' (Segment: '' )
Server: true (Bootstrap: false)
Client Addr: [0.0.0.0] (HTTP: 8500, HTTPS: -1, gRPC: -1, DNS: 8600)
Cluster Addr: 172.17.0.2 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false
==> Log data will now stream in as it occurs:
......
可用得知,其docker内的IP
地址为 172.17.0.2
此外,还可以使用:
## 或者使用 docker inspect ConsulServer-1
root@cchui-virtual-machine:~# docker inspect 3f84110d97ab
[
{
"Id": "3f84110d97ab1b8569dfc90c700f37052ea27ba0514259251d92f36a693ffa8e",
"Created": "2021-04-29T07:25:15.831391139Z",
"Path": "docker-entrypoint.sh",
"Args": [
"agent",
"-server",
"-ui",
"-node=Server-A",
"-bootstrap-expect=3",
"-client=0.0.0.0"
],
......
"NetworkSettings": {
......
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "63a7356e019829b92981ba76fff8e0323e65bb97c5045d03f1a7900d47d6d35b",
"EndpointID": "7daf65d294211b6ecd69df208bacc58530bb4b5f4374d98916320590e24115c1",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
之后,再启动其他两个docker:
启动另外两个server节点
# 启动节点B
docker run -d -p 8501:8500 --name=ConsulServer-2 consul agent -server -ui -node=Server-B -bootstrap-expect=3 -client=0.0.0.0 -join=172.17.0.2
# 启动节点C
docker run -d -p 8502:8500 --name=ConsulServer-3 consul agent -server -ui -node=Server-C -bootstrap-expect=3 -client=0.0.0.0 -join=172.17.0.2
说明:
-d
,以后台运行的方式,在后台运行查看节点A日志
可以看到,之前,一直是有日志错误:
2021-04-29T07:33:21.542Z [ERROR] agent: Coordinate update error: error="No cluster leader"
2021-04-29T07:33:24.034Z [ERROR] agent.anti_entropy: failed to sync remote state: error="No cluster leader"
表示当前没有Raft
的leader
。
但是,当三个节点连接成网后,一段时间后,就开始选举领导者,同步数据了:
root@cchui-virtual-machine:~# docker run -it -p 8500:8500 --name=ConsulServer-1 consul agent -server -ui -node=Server-A -bootstrap-expect=3 -client=0.0.0.0
==> Starting Consul agent...
......
==> Log data will now stream in as it occurs:
......
==> Consul agent running!
2021-04-29T07:52:38.401Z [ERROR] agent.anti_entropy: failed to sync remote state: error="No cluster leader"
2021-04-29T07:52:38.742Z [WARN] agent.server.raft: no known peers, aborting election
# 节点 Server-B 加入集群
2021-04-29T07:52:59.231Z [INFO] agent.server.serf.lan: serf: EventMemberJoin: Server-B 172.17.0.3
......
# 节点 Server-C 加入集群
2021-04-29T07:53:06.841Z [INFO] agent.server.serf.lan: serf: EventMemberJoin: Server-C 172.17.0.4
......
# 开始进行 Raft 选举 leader
2021-04-29T07:53:10.416Z [WARN] agent.server.raft: heartbeat timeout reached, starting election: last-leader=
# Server-A 成为候选者 Candidate
2021-04-29T07:53:10.416Z [INFO] agent.server.raft: entering candidate state: node="Node at 172.17.0.2:8300 [Candidate]" term=2
2021-04-29T07:53:10.428Z [INFO] agent.server.raft: election won: tally=2
# Server-A 成为领导者 Leader
2021-04-29T07:53:10.428Z [INFO] agent.server.raft: entering leader state: leader="Node at 172.17.0.2:8300 [Leader]"
......
2021-04-29T07:53:10.429Z [INFO] agent.server: New leader elected: payload=Server-A
......
# 开始同步数据
2021-04-29T07:53:10.533Z [INFO] agent: Synced node info
最终,选举节点A作为领导者:
通过查看web网页,也可以看到leader:
http://IP:8501/ui/dc1/nodes
启动第一个客户端:
docker run -it -p 9001:9001 --name=ConsulClient-1 consul agent -node=Client-1 -client=0.0.0.0 -join 172.17.0.2
此Docker运行的是Consul Client模式,并加入了Consul Server A(加入那个Consul Server都可以)。
# 启动第二个客户端
docker run -d -p 9002:9001 --name=ConsulClient-2 consul agent -node=Client-2 -client=0.0.0.0 -join 172.17.0.3
# 启动第三个客户端
docker run -d -p 9003:9001 --name=ConsulClient-3 consul agent -node=Client-3 -client=0.0.0.0 -join 172.17.0.4
查看界面:
docker stop $(docker ps -aq)