服务发现组件:Consul简易攻略

简介

  Consul是一种分布式、高可用性、支持多数据中心的解决方案,可动态、分布式基础架构连接和配置的应用程序。

特性

  • 『多数据中心』

    Consul是为支持数据中心而构建的,可以支持任意数量的区域,而无需复杂的配置。
  • 『服务网格』

    Consul服务网格通过自动TLS加密和基于身份的授权实现安全的服务到服务通信。应用程序可以在服务网格配置中使用sidecar代理,通过透明代理为入站和出站连接建立TLS连接。
  • 『服务发现』

    Consul使服务注册自己和通过DNSHTTP接口发现其他服务变得简单。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)能力实现交互。

途径备注
WebUIConsul服务启动后访问 http://{ip}:8500/ui
API、Command(Cli)Consul Command(Cli)
API

Command(Cli)

  如下是Consul支持的命令清单,关于命令集操作大部分都是开源版本支持的,部分是需要商业版才可以支持,这里只关注开源版常用命令。

命令说明
acl访问控制交互
agent运行Consul的代理
catalog目录交互
connectConsul连接相关
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.3110.211.55.3210.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.3210.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变化:

### 先创建一个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的交互调试,推荐使用PostmanHttp工具,API的功能和Command(Cli)提供的能力相仿,可参考文档自行测试。Consul API

源码解读

架构概览

image.png

  上图是Consul官方提供的架构示意图,解读如下:

  • 支持多机房部署,跨机房通过局域网Gossip协议进行通信
  • 每个机房有多个Client、Server模块构成,职责如下
    • Client: 客户端,无状态,将Http/DNS接口请求转发给局域网内的服务端集群,主要作用是做服务代理进行请求转发,和具体服务进行交互,在大规模集群下很快就会膨胀到成千上万个。
    • Server: 服务端,保持配置信息,高可用集群,每个数据中心的server数量推荐为3个或者5个,通过Raft协议进行通信,是CP的实现,极端情况下保证数据一致性牺牲可用性。

源码结构

如果觉得每个模块的源码太多,梳理不清楚逻辑关系,可参考Goland中使用GoPlantUml生成ER关系图 进行ER图拆解。

  首先,将1.4.2版本代码结构整理成了思维导图,绿色背景模块是个人认为较为重要的目录,学习时可以重点关注。

Consul源码 (2).png

功能特性

  工程目录中contributing、docs两个目录文档内容是非常好的Consul源码学习材料,它能有效地引导我们快速认识Consul

  • contributing是概括性内容,便于了解全貌。
  • docs是每个模块详细介绍,便于了解细节。

  下面我们借助两个目录文档内容来剖析下Consul的核心功能模块,如下:

image.png

模块介绍
Command-Line Interface (CLI)- 基于https://github.com/mitchellh/cli 实现的命令行交互工具,这部分的核心代码在目录command中,可以在main.go查看Cli的启动进行溯源跟踪。
HTTP API- 这部分的核心代码在目录api中,使用了Go官方的API库,ConsulCLI命令也使用该客户端与本地Consul代理进行通信。
Agent Configuration- 代理配置是配置Consul的主要机制。代理配置还允许指定代理启动时将加载的配置条目、服务和检查。
- 大多数配置来自hcljson文件,但也可以使用命令行标志指定某些配置,也可以使用Auto Config加载某些配置。
- 这部分核心代码在目录agent/config
RPC-Consul使用两个RPC系统在集群内的组件之间以及其他客户端之间进行通信,gRPCGonet/RPC包。
- 客户端代理和服务器之间的通信混合使用gRPCnet/rpc。一般来说,gRPC是首选的,因为它支持诸如上下文、截止日期、取消、流和中间件等功能,但Consul已经存在了一段时间,因此大多数RPC端点仍然使用net/RPC。大多数集群内通信都是通过多路复用的“服务器”TCP端口进行的(默认值:8300)。Consul服务器实现了一个自定义协议,用于在同一端口上服务不同类型的流量,其中发送的第一个字节表示协议(例如gRPCnet/rpcRaft)。在单个服务器端口上复用多个协议有助于减少网络需求,但也让使用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 StoreKV存储相关
ACLACL子系统负责验证和授权对Consul操作HTTP-APIRPC的访问。
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协议

Consul一致性协议介绍

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服务器都出现故障,则可以使用快照将群集恢复到以前的状态。

  需要注意的是,在不同的层中存在两种不同的快照和恢复概念。首先是raftFSM接口上的SnapshotRestore方法,Consul必须实现这些方法。这些方法主要通过状态存储来实现。这些方法可以由raft内部调用,以执行日志压缩(快照)或引导新的跟随器(恢复)。Consul的快照和还原类型实现快照和还原的核心代码在agent/consul/state

  快照和还原也作为用户可以执行的操作存在。有CLI命令、HTTP API端点和RPC端点,允许用户捕获包含状态快照的存档,并将该状态还原到正在运行的集群。consul/snapshot为用户创建和读取快照存档提供了一些逻辑。有关这些面向用户的操作的参考,请参见consul/snapshot

  最后,还有一个快照代理(仅限企业版),它使用快照API端点定期捕获快照,并可选择将其发送到某个存储位置。

Gossip协议

Consul Gossip协议介绍

image.png

  Consul使用LAN Gossip PoolWAN Gossip Pool来执行不同的功能。这些协议池能够通过利用嵌入式Serf库来执行其功能。Consul对库进行了抽象和屏蔽,以简化用户体验和操作的复杂度。

局域网通信池(LAN Gossip Pool)

  Consul所在的每个数据中心都有一个包含数据中心所有成员(客户端和服务器)的LAN Gossip PoolLAN Gossip Pool提供的成员信息允许客户端自动发现服务器,从而减少所需的配置量。故障检测也由整个集群分布和共享,而不是集中在几个服务器上,LAN Gossip Pool可以快速可靠的进行事件广播。

广域网通信池(WAN Gossip Pool)

  WAN Gossip Pool是全球唯一的,无论数据中心如何,所有服务器都应参与WAN Gossip PoolWAN Gossip Pool提供的成员信息允许服务器执行跨数据中心请求。集成故障检测允许Consul优雅地处理连接丢失,无论是整个数据中心还是远程数据中心中的单个服务器。

参考资料

目前最新版本为1.4.2,本篇以此版本为参考。

Consul官网

Consul官方文档

Github源码地址

简易的入门视频

🏄🏄🏄 如果觉得有所收获,欢迎 『点赞』、『收藏』、『关注』 一键三连支持喔~
posted @ 2023-01-06 21:52  大摩羯先生  阅读(232)  评论(0编辑  收藏  举报