简介
Consul
是一种分布式、高可用性、支持多数据中心的解决方案,可动态、分布式基础架构连接和配置的应用程序。
特性
- 『多数据中心』
Consul
是为支持数据中心而构建的,可以支持任意数量的区域,而无需复杂的配置。 - 『服务网格』
Consul
服务网格通过自动TLS
加密和基于身份的授权实现安全的服务到服务通信。应用程序可以在服务网格配置中使用sidecar
代理,通过透明代理为入站和出站连接建立TLS
连接。 - 『服务发现』
Consul
使服务注册自己和通过DNS
或HTTP
接口发现其他服务变得简单。SaaS
提供商等外部服务也可以注册。 - 『健康检查』
健康检查使Consul
能够快速提醒和反馈集群中的任何问题,与服务发现的集成可防止将流量路由到不健康的主机,并启用服务级别断路器。 - 『键值对存储』
灵活的键值对存储器支持存储动态配置、功能标记、协调、Leader选举等。简单的HTTP API
使其易于在任何地方使用。
Consul
支持在Linux、macOS、FreeBSD、Solaris、Windows
系统上运行,提供了交互友好的Web UI
管理,也提供了Consul Enterprise
的商业版本。
环境安装
MacOS系统,依赖xcode版本,不符合的可以升级下版本
brew tap hashicorp/tap
brew install hashicorp/tap/consul
Consul使用
关于Consul的使用主要可以通过两种途径完成,一种通过原生支持的WebUI
进行可视化管理,另一种是通过API、Command(Cli)
能力实现交互。
途径 | 备注 |
---|---|
WebUI | Consul服务启动后访问 http://{ip}:8500/ui |
API、Command(Cli) | Consul Command(Cli) API |
Command(Cli)
如下是Consul支持的命令清单,关于命令集操作大部分都是开源版本支持的,部分是需要商业版才可以支持,这里只关注开源版常用命令。
命令 | 说明 |
---|---|
acl | 访问控制交互 |
agent | 运行Consul的代理 |
catalog | 目录交互 |
connect | Consul连接相关 |
debug | 支持debug模式调试 |
event | 启动一个新事件 |
exec | 在Consul节点上执行命令 |
force-leave | 强制集群成员进入“left”状态 |
info | 提供调试信息 |
intention | 交互连接服务意向 |
join | 通知Consul代理加入集群 |
keygen | 生成新的加密密钥 |
keyring | 管理gossip层的加密密钥 |
kv | 交互KV存储 |
leave | 优雅地离开Consul集群并关闭 |
lock | 执行持有锁的命令 |
login | 使用身份验证方法登录Consul |
logout | 销毁使用登录创建的Consul令牌 |
maint | 控制节点或服务维护模式 |
members | 输出Consul集群中的节点信息 |
monitor | 从Consul代理流式传输日志 |
operator | 提供操作集群的工具 |
peering | 创建、管理Consul集群之间的对等连接 |
reload | 触发代理重新加载配置文件 |
rtt | 评估节点之间的网络往返时间 |
services | 和服务进行交互 |
snapshot | 保存、恢复和检查Consul服务器状态的快照 |
tls | 用于创建CA和证书的内置帮助程序 |
validate | 验证配置文件/目录 |
version | 输出Consul版本 |
watch | 监听Consul变化 |
下面我们通过串联实际案例体验下核心的Command(Cli)
和API
来操作交互,如下:
查看版本
当安装完成后,可以执行如下查看当前Consul版本号,这里我们使用的当前最新的v1.14.2
版本。
[parallels@localhost bin]$ ./consul --version
Consul v1.14.2
Revision 0ba7a401
Build Date 2022-11-30T19:54:31Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
服务启动
服务启动可以通过debug、server模式来进行。
debug模式下,可以支持单节点启动,适合本地测试,不需要多服务器节点来搭建集群。
# -server 以服务模式启动
# -bind 绑定服务IP
# -client 允许所有IP访问
# -ui 打开可视化页面
# -data-dir 数据存储路径
# -node 节点名称
[parallels@localhost bin]$ ./consul agent -dev -bind=192.168.0.101 -client=0.0.0.0 -ui -data-dir=/usr/local/consul/data/ -node=server-01
server模式下,需要最少3个节点共同支持方可完成启动。
为了避免网络通信产生问题,可先关闭服务器防火墙设置,如下:
systemctl stop firewalld
systemctl disable firewalld
这里准备了三台服务器10.211.55.31
、10.211.55.32
、10.211.55.33
,分别以Server模式启动,如下:
# -server 以服务模式启动
# -bind 绑定服务IP
# -client 允许所有IP访问
# -ui 打开可视化页面
# -bootstrap-expect 集群节点数量,最少3个,最多建议5个
# -data-dir 数据存储路径
# -node 节点名称
[parallels@localhost bin]$ ./consul agent -server -bind=10.211.55.31 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data/ -node=server-01
[parallels@localhost bin]$ ./consul agent -server -bind=10.211.55.32 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data/ -node=server-02
[parallels@localhost bin]$ ./consul agent -server -bind=10.211.55.33 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data/ -node=server-03
启动后的Server节点并不会自动完成Leader选举,需要完成join
命令操作完成加入操作,这里让10.211.55.31
成为Leader,需要在10.211.55.32
、10.211.55.33
机器上执行如下命令进行加入,如下:
[parallels@localhost bin]$ ./consul join 10.211.55.31
查看集群成员信息
当加入完节点后,我们再来查看下当前集群的成员信息,可以看到节点名称、地址端口、节点状态、节点类型、机房等信息。
[parallels@localhost bin]$ ./consul members
Node Address Status Type Build Protocol DC Partition Segment
server-01 10.211.55.31:8301 alive server 1.14.2 2 dc1 default <all>
server-02 10.211.55.32:8301 alive server 1.14.2 2 dc1 default <all>
server-03 10.211.55.33:8301 alive server 1.14.2 2 dc1 default <all>
Raft视角相关操作
由于Consul集群是基于Raft
协议来构建的,Cli操作也提供了Raft
视角的一些查看、处理操作。
### 可以看到10.211.55.31当前是leader节点,其余两个是follower节点
[parallels@localhost bin]$ ./consul operator raft list-peers
Node ID Address State Voter RaftProtocol
server-03 996beb1a-ffa3-a621-d384-e355a1edeb37 10.211.55.33:8300 leader true 3
server-01 0c117b67-d283-6b5d-98bd-217d829cda9e 10.211.55.31:8300 follower true 3
server-02 0fb2224a-0ad4-7053-1bea-0c89a408d569 10.211.55.32:8300 follower true 3
### 指定IP+PORT踢出节点不再参与Raft协议过程,适合处理节点异常的情况
consul operator raft remove-peer -address=10.211.55.33:8300
Removed peer with address "10.211.55.33:8300"
查看目录信息
### 节点信息
[parallels@localhost bin]$ ./consul catalog nodes
Node ID Address DC
server-01 0c117b67 10.211.55.31 dc1
server-02 0fb2224a 10.211.55.32 dc1
server-03 996beb1a 10.211.55.33 dc1
### 服务信息
[parallels@localhost bin]$ ./consul catalog services
consul
### 数据中心、机房信息
[parallels@localhost bin]$ ./consul catalog datacenters
dc1
查看Consul元数据
提供了Consul运维管理层面的元数据查看能力
### - agent: 提供agent相关信息
### - consul: 提供当前节点的Consul信息
### - raft: 提供Raft一致性协议信息 (https://developer.hashicorp.com/consul/docs/architecture/consensus)
### - serf_lan:提供本地局域网Gossip协议信息 (https://developer.hashicorp.com/consul/docs/architecture/gossip)
### - serf_wan:提供广域网Gossip协议信息(https://developer.hashicorp.com/consul/docs/architecture/gossip)
[parallels@localhost bin]$ ./consul info
agent:
check_monitors = 0
check_ttls = 0
checks = 0
services = 0
build:
prerelease =
revision = 0ba7a401
version = 1.14.2
version_metadata =
consul:
acl = disabled
bootstrap = false
known_datacenters = 1
leader = false
leader_addr = 10.211.55.31:8300
server = true
raft:
applied_index = 47
commit_index = 47
fsm_pending = 0
last_contact = 78.947472ms
last_log_index = 47
last_log_term = 2
last_snapshot_index = 0
last_snapshot_term = 0
latest_configuration = [{Suffrage:Voter ID:0c117b67-d283-6b5d-98bd-217d829cda9e Address:10.211.55.31:8300} {Suffrage:Voter ID:0fb2224a-0ad4-7053-1bea-0c89a408d569 Address:10.211.55.32:8300} {Suffrage:Voter ID:996beb1a-ffa3-a621-d384-e355a1edeb37 Address:10.211.55.33:8300}]
latest_configuration_index = 0
num_peers = 2
protocol_version = 3
protocol_version_max = 3
protocol_version_min = 0
snapshot_version_max = 1
snapshot_version_min = 0
state = Follower
term = 2
runtime:
arch = amd64
cpu_count = 2
goroutines = 126
max_procs = 2
os = linux
version = go1.19.2
serf_lan:
coordinate_resets = 0
encrypted = false
event_queue = 0
event_time = 2
failed = 0
health_score = 0
intent_queue = 0
left = 0
member_time = 3
members = 3
query_queue = 0
query_time = 1
serf_wan:
coordinate_resets = 0
encrypted = false
event_queue = 0
event_time = 1
failed = 0
health_score = 0
intent_queue = 0
left = 0
member_time = 3
members = 3
query_queue = 0
query_time = 1
操作KV存储
构建完集群后我们来向Consul中做KV
数据操作,如下:
### 存储key为user,value为zhangsan的数据
[parallels@localhost bin]$ ./consul kv put user zhangsan
Success! Data written to: user
### 查看当前KV数据,value存储格式是base64
[parallels@localhost bin]$ ./consul kv export
[
{
"key": "user",
"flags": 0,
"value": "emhhbmdzYW4="
}
]
### 指定key查看数据
[parallels@localhost bin]$ ./consul kv get user
zhangsan
### 指定key删除数据
[parallels@localhost bin]$ ./consul kv delete user
Success! Deleted key: user
查看节点间延迟
可以检查节点之间的网络延迟情况。
### 查看server-01 server-02之间
[parallels@localhost bin]$ ./consul rtt server-01 server-02
Estimated server-01 <-> server-02 rtt: 1.235 ms (using LAN coordinates)
### 查看server-01 server-03之间
[parallels@localhost bin]$ ./consul rtt server-01 server-03
Estimated server-01 <-> server-03 rtt: 1.261 ms (using LAN coordinates)
### 查看server-02 server-03之间
[parallels@localhost bin]$ ./consul rtt server-02 server-03
Estimated server-02 <-> server-03 rtt: 1.157 ms (using LAN coordinates)
注册注销服务
### 注册client-01服务
[parallels@localhost bin]$ ./consul services register -name=client-01
Registered service: client-01
### 查看服务列表
[parallels@localhost bin]$ ./consul catalog services
client-01
consul
### 注销client-01服务
[parallels@localhost bin]$ ./consul services deregister -id=client-01
Deregistered service: client-01
### 查看服务列表
[parallels@localhost bin]$ ./consul catalog services
consul
监听器使用
监听器支持如下形式监听:
key
- 监听指定键值对keyprefix
- 监控指定键前缀services
- 监听service服务列表nodes
- 监听nodes节点列表service
- 监听service实例checks
- 监听健康检查event
- 监听用户事件
下面演示监听指定key
变化:
### 先创建一个sh脚本,内容为 echo 'key is changed'
[root@localhost bin]# touch shell.sh
### 配置监听key为user的命令,该key变化后会执行shell.sh脚本,此时会挂起
[root@localhost bin]# ./consul watch -type=key -key=user /usr/local/bin/shell.sh
### 修改key为user的值
[parallels@localhost bin]$ ./consul kv put user lisi
Success! Data written to: user
### 监听到key的变化调用shell.sh
[root@localhost bin]# ./consul watch -type=key -key=user /usr/local/bin/shell.sh
key is changed
API
API的交互调试,推荐使用Postman
等Http
工具,API
的功能和Command(Cli)
提供的能力相仿,可参考文档自行测试。Consul API。
源码解读
架构概览
上图是Consul
官方提供的架构示意图,解读如下:
- 支持多机房部署,跨机房通过局域网
Gossip
协议进行通信 - 每个机房有多个Client、Server模块构成,职责如下
- Client: 客户端,无状态,将
Http/DNS
接口请求转发给局域网内的服务端集群,主要作用是做服务代理进行请求转发,和具体服务进行交互,在大规模集群下很快就会膨胀到成千上万个。 - Server: 服务端,保持配置信息,高可用集群,每个数据中心的server数量推荐为3个或者5个,通过
Raft
协议进行通信,是CP
的实现,极端情况下保证数据一致性牺牲可用性。
- Client: 客户端,无状态,将
源码结构
如果觉得每个模块的源码太多,梳理不清楚逻辑关系,可参考Goland中使用GoPlantUml生成ER关系图 进行ER图拆解。
首先,将1.4.2
版本代码结构整理成了思维导图,绿色背景模块是个人认为较为重要的目录,学习时可以重点关注。
功能特性
工程目录中contributing、docs
两个目录文档内容是非常好的Consul
源码学习材料,它能有效地引导我们快速认识Consul
。
contributing
是概括性内容,便于了解全貌。docs
是每个模块详细介绍,便于了解细节。
下面我们借助两个目录文档内容来剖析下Consul
的核心功能模块,如下:
模块 | 介绍 |
---|---|
Command-Line Interface (CLI) | - 基于https://github.com/mitchellh/cli 实现的命令行交互工具,这部分的核心代码在目录command 中,可以在main.go 查看Cli 的启动进行溯源跟踪。 |
HTTP API | - 这部分的核心代码在目录api 中,使用了Go 官方的API 库,Consul 的CLI 命令也使用该客户端与本地Consul 代理进行通信。 |
Agent Configuration | - 代理配置是配置Consul 的主要机制。代理配置还允许指定代理启动时将加载的配置条目、服务和检查。- 大多数配置来自 hcl 或json 文件,但也可以使用命令行标志指定某些配置,也可以使用Auto Config 加载某些配置。- 这部分核心代码在目录 agent/config 。 |
RPC | -Consul 使用两个RPC 系统在集群内的组件之间以及其他客户端之间进行通信,gRPC 、Go 的net/RPC 包。- 客户端代理和服务器之间的通信混合使用 gRPC 和net/rpc 。一般来说,gRPC 是首选的,因为它支持诸如上下文、截止日期、取消、流和中间件等功能,但Consul 已经存在了一段时间,因此大多数RPC 端点仍然使用net/RPC 。大多数集群内通信都是通过多路复用的“服务器”TCP 端口进行的(默认值:8300)。Consul 服务器实现了一个自定义协议,用于在同一端口上服务不同类型的流量,其中发送的第一个字节表示协议(例如gRPC 、net/rpc 、Raft )。在单个服务器端口上复用多个协议有助于减少网络需求,但也让使用grpcurl 等本地开发工具与Consul 进行交互变得困难。- 这部分的核心代码在目录 agent/consul/rpc.go 。 |
Cluster Persistence | - 集群持久化子系统完全在服务器代理中运行。它处理来自RPC 子系统的读和写请求。- 有关 Consul 部署体系结构和集群持久化子系统使用的共识协议的介绍,可以参阅Consul 体系结构指南。- 这部分主要是基于 Raft 共识协议实现 |
Client Agent | 客户端代理核心代码主要有以下部分: - agent/cache - agent/local - agent/ae 客户端节点上的应用程序在客户端模式下使用其本地代理来注册服务,并发现其他服务或与密钥/值存储交互 |
Service Discovery | 服务发现包含如下部分: - Catalog,是服务发现和服务网格的核心。它接受服务、节点和检查的注册和注销。 - DNS Interface,DNS接口允许用户使用DNS查询查找服务的IP地址和端口,DNS接口在许多方面类似于HTTP API,主要区别在于DNS协议的不同。 - Health Checks |
Service Mesh (Connect) | 服务网格 |
Cluster Membership | 集群成员关系包含如下: - hashicorp/serf - hashicorp/memberlist - network coordinates - consul events - consul exec 客户机和服务器模式代理都参与 Gossip 协议,该协议提供了两种重要机制。- 首先,它允许代理了解集群中的所有其他代理,只需最初加入集群的单个现有成员即可。这允许客户端发现新的 Consul 服务器。- 其次, Gossip 协议提供了一个分布式故障检测器,集群中的代理以规则的间隔随机探测彼此。由于有了这个故障检测器,Consul 可以在每个代理上本地运行运行状况检查,并在运行状况检查的状态发生变化时发送边缘触发的更新,确信如果代理完全死亡,那么集群将检测到这一点。这使得Consul 的健康检查设计与具有中央轮询类型设计的集中式系统相比非常可扩展。 |
Key/Value Store | KV存储相关 |
ACL | ACL 子系统负责验证和授权对Consul 操作HTTP-API 和RPC 的访问。 |
Multi-Cluster Federation | 这部分主要是企业版功能 |
协议
在Consul
中,数据一致性使用到Raft
协议完成,节点通信使用到Gossip
协议完成。可以说一致性协议、通信协议
两大协议簇撑起了分布式服务及其组件的理论基础和技术底盘,类似的还有Redis、Kafka、RocketMQ
等。
协议 | 实现 | 作用 |
---|---|---|
Raft | 基于HashiCorp自己的https://github.com/hashicorp/raft | 数据一致性管理,协商、投票、Leader选举等 |
Gossip | 基于HashiCorp自己的 https://www.serf.io/ 实现 | 集群节点通信,处理节点发现、故障检测等 |
在这里真的很佩服hashicorp这家公司,大家感兴趣可以在在Github上找到该公司的开源库。
Raft协议
Raft和FSM
hashicorp/raft是集群持久性的核心。Raft
需要FSM
(一种有限状态机实现)来持久化状态更改。Consul FSM
作为一组命令的核心代码在目录agent/consul/fsm
。
Raft
还需要LogStore将日志持久化到磁盘。Consul
使用hashicorp/raft-boltdb,它使用boltdb.实现LogStore。在不久的将来,推荐使用bbolt。
状态存储
Consul
使用状态存储将集群的完整状态存储在内存中。状态存储在agent/consul/state实现,并使用hashicorp/go-memdb维护存储在一组表中的数据索引,状态存储的主要入口点是NewStateStore。
表/结构/索引
状态存储被组织为一组表,每个表都有一组索引。架构中的schema.go显示表的完整列表,每个模式函数显示索引的完整列表。
定义表索引有两种样式。原始样式使用来自hashicorp/go-memdb(例如StringFieldIndex
)的通用索引器实现。这些索引使用reflect查找索引的值。当索引值是直接从struct
字段中获得的单个值,并且没有oss/enterprise
差异时,这些通用索引器工作得很好。
第二种类型的索引器是仅使用函数并基于indexer.go中定义的类型实现的自定义索引器。当索引值是从一个或多个字段派生的值时,或者当索引之间存在oss/enterprise
差异时,这种类型的索引非常有效。
快照/恢复
快照(snapshot) 是用于备份集群持久性存储的数据的主要机制。如果所有Consul
服务器都出现故障,则可以使用快照将群集恢复到以前的状态。
需要注意的是,在不同的层中存在两种不同的快照和恢复概念。首先是raft
FSM接口上的Snapshot
和Restore
方法,Consul
必须实现这些方法。这些方法主要通过状态存储来实现。这些方法可以由raft
内部调用,以执行日志压缩(快照)或引导新的跟随器(恢复)。Consul
的快照和还原类型实现快照和还原的核心代码在agent/consul/state。
快照和还原也作为用户可以执行的操作存在。有CLI
命令、HTTP API
端点和RPC
端点,允许用户捕获包含状态快照的存档,并将该状态还原到正在运行的集群。consul/snapshot为用户创建和读取快照存档提供了一些逻辑。有关这些面向用户的操作的参考,请参见consul/snapshot。
最后,还有一个快照代理(仅限企业版),它使用快照API
端点定期捕获快照,并可选择将其发送到某个存储位置。
Gossip协议
Consul
使用LAN Gossip Pool
和WAN Gossip Pool
来执行不同的功能。这些协议池能够通过利用嵌入式Serf
库来执行其功能。Consul
对库进行了抽象和屏蔽,以简化用户体验和操作的复杂度。
局域网通信池(LAN Gossip Pool)
Consul
所在的每个数据中心都有一个包含数据中心所有成员(客户端和服务器)的LAN Gossip Pool
。LAN Gossip Pool
提供的成员信息允许客户端自动发现服务器,从而减少所需的配置量。故障检测也由整个集群分布和共享,而不是集中在几个服务器上,LAN Gossip Pool
可以快速可靠的进行事件广播。
广域网通信池(WAN Gossip Pool)
WAN Gossip Pool
是全球唯一的,无论数据中心如何,所有服务器都应参与WAN Gossip Pool
。WAN Gossip Pool
提供的成员信息允许服务器执行跨数据中心请求。集成故障检测允许Consul
优雅地处理连接丢失,无论是整个数据中心还是远程数据中心中的单个服务器。
参考资料
目前最新版本为
1.4.2
,本篇以此版本为参考。
Consul官网
Consul官方文档
Github源码地址
简易的入门视频
🏄🏄🏄 如果觉得有所收获,欢迎 『点赞』、『收藏』、『关注』 一键三连支持喔~