简介
Consul,HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更一站式,内置服务注册与发现框架、分布一致性协议实现、健康检查、K/V存储、多数据中心方案,不再需要依赖其他工具(如ZooKeeper等)。使用Go语言编写,具有天然可移植性;安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合。
GitHub开源地址。
概念
- Agent:agent是长期运行在每个Consul集群成员节点上的守护进程。通过
consul agent
命令启动,agent有client和server两种模式。由于每个节点都必须运行agent,所以节点要么是client要么是server。所有的agent都可以调用DNS或HTTP API,并负责检查和维护服务同步 - Client:运行client模式的agent,将所有的RPC转发到server。client是相对无状态的。client唯一所做的是在后台参与LAN gossip pool。只消耗少量的资源和少量的网络带宽
- Server:运行server模式的agent,参与Raft quorum,维护集群状态,响应RPC查询,与其他数据中心交互WAN gossip,转发查询到Leader或远程数据中心
- DataCenter:定义数据中心在同一个网络环境中:私有的、低延迟、高带宽。这不包括基于公共互联网的环境,在同一个EC2中的多个可用性区域会被认为是在同一个数据中心中
- Consensus:意味着Leader election机制,以及事务的顺序。由于这些事务基于一个有限状态机,consensus的定义意味着复制状态机的一致性
- Gossip:Consul建立在Serf之上,提供完整的Gossip协议,用于成员维护故障检测、事件广播,Gossip的节点到节点之间的通信使用UDP协议
- LAN Gossip:LAN gossip pool,指在同一局域网或数据中心的节点上的LAN Gossip池
- WAN Gossip:WAN gossip pool,只包含server节点,这些server主要分布在不同的数据中心,通过网络进行通信
- RPC:远程过程调用,允许client请求server的请求/响应机制
功能
- 服务发现:Consul客户端可向Consul注册服务,其他客户端可以使用Consul来发现服务的提供者。支持使用DNS或HTTP两种方式
- 健康检查:Consul客户端可以提供任意数量的运行状况检查机制,这些检查机制可以与给定服务(Web服务器返回200 OK)或本地节点(内存利用率低于90%)相关联。这些信息可以用来监控群集的运行状况,服务发现组件可以使用监控信息来路由流量,使流量远离不健康的服务
- KV存储:应用程序可以将Consul的键/值存储起来用于任何需求,包括动态配置、功能标记、协调、领导者选举等。KV存储采用HTTP API,易于使用
- 安全服务通信:Consul可以为服务生成和分发TLS证书,以建立相互的TLS连接
- 多数据中心:Consul支持多个数据中心,这意味着Consul用户不必担心构建额外的抽象层来扩展到多个区域
适用场景
至少包括如下场景:
- 健康检查
- 节点实例的注册与配置共享,如Docker、CoreOS等系统
- vitess集群
- 与confd服务集成,动态生成Nginx和HaProxy配置文件
架构
官网给出的架构示意图:
大概分析下,Consul高可用集群由一个个DC(DataCenter)组成,DC之间的通信采用Gossip协议。
一个DC下有若干个Server节点,节点间通过集群选举算法选出一个Leader和若干个Follower,Leader负责处理所有查询和事务,当Follower收到RPC请求时,它会将其转发给集群Leader。Leader和Follower基于TCP协议和8300端口进行集群状态数据同步。
不同的Consul数据中心之间不会复制数据。
安装
具体的安装步骤因操作系统和部署模式不同而有所不同。
系统
Linux
以CentOS系统为例:
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install consul
Mac OS
通过brew来安装:
brew tap hashicorp/tapbrew install hashicorp/tap/consul
安装成功
# 查看版本号
consul --version
# 前台启动
consul agent -dev
# 后台启动示例
consul agent -server -ui -bootstrap-expect=1 -client=0.0.0.0 -bind <ip地址> -data-dir=/<状态数据存储文件夹>/data >> /<日志记录文件夹>/logs/consul.log &
# 准备目录
mkdir -p /usr/local/var/logs/consul/
touch consul.log
consul agent -server -ui -bootstrap-expect=1 -client=0.0.0.0 -bind 127.0.0.1 -data-dir=/usr/local/var/consul/data >> /usr/local/var/logs/consul/consul.log &
# 查看服务
ps aux | grep -v grep | grep consul
正常来说,命令执行成功,浏览器打开http://localhost:8500
,即可访问。如果浏览器打不开此地址,说明启动失败,查看启动日志:cat /usr/local/var/logs/consul/consul.log
模式
单机
上面几种安装方式就是单机安装。
集群
待补充。
基础
端口
Consul中默认的端口:
- 服务器RPC:默认8300,由服务器用来处理来自其他代理的传入请求,仅限TCP
- Serf LAN:默认8301,用来处理局域网中的八卦。所有代理都需要,TCP和UDP
- Serf WAN:默认8302,被服务器用来在WAN上闲聊到其他服务器,TCP和UDP。通过端口8302在LAN接口上为TCP和UDP启用服务器之间的连接,以及WAN加入泛滥功能
- HTTP API:默认8500,被客户用来与HTTP API交谈,仅限TCP
- DNS接口:默认8600,用于解析DNS查询,TCP和UDP。
命令
执行Consul命令后的输出:
Available commands are:agent Runs a Consul agentcatalog Interact with the catalogevent Fire a new eventexec Executes a command on Consul nodesforce-leave Forces a member of the cluster to enter the "left" stateinfo Provides debugging information for operators.join Tell Consul agent to join clusterkeygen Generates a new encryption keykeyring Manages gossip layer encryption keyskv Interact with the key-value storeleave Gracefully leaves the Consul cluster and shuts downlock Execute a command holding a lockmaint Controls node or service maintenance modemembers Lists the members of a Consul clustermonitor Stream logs from a Consul agentoperator Provides cluster-level tools for Consul operatorsreload Triggers the agent to reload configuration filesrtt Estimates network round trip time between nodessnapshot Saves, restores and inspects snapshots of Consul server statevalidate Validate config files/directoriesversion Prints the Consul versionwatch Watch for changes in Consul
consul agent
Consul的Agent是Consul的核心。Agent维护成员的信息,注册服务,运行检测,响应查询。Agent必须作为Consul集群的一部分的每个节点上运行。任何代理可以以两种模式之一运行:客户端或服务器。服务器节点承担协商一致性的功能。这些节点参与Raft,并在故障下提供强大的一致性和可用性。服务器节点负担越来越大意味着需要在专用的实例上运行——他们比客户端节点更为资源密集。客户端节点构成了大多数的集群,并且它们很轻量,因为它们大多数操作的是服务器节点接口,维护自己状态的时间很少。
consul agent --help
:
-data-dir
作用:指定agent储存状态的数据目录
这是所有agent都必须的
对于server尤其重要,因为他们必须持久化集群的状态
-config-dir
作用:指定service的配置文件和检查定义所在的位置
通常会指定为”某一个路径/consul.d”(.d
表示一系列配置文件存放的目录)
-config-file
作用:指定一个要装载的配置文件
该选项可以配置多次,进而配置多个配置文件(后边的会合并前边的,相同的值覆盖)
-dev
作用:创建一个开发环境下的server节点
该参数配置下,不会有任何持久化操作,即不会有任何数据写入到磁盘
这种模式不能用于生产环境
-bootstrap-expect
该命令通知consul server我们现在准备加入的server节点个数,该参数是为了延迟日志复制的启动直到我们指定数量的server节点成功的加入后启动。
-node
作用:指定节点在集群中的名称
该名称在集群中必须是唯一的(默认采用机器的host)
推荐:直接采用机器的IP
-bind
作用:指明节点的IP地址
有时候不指定绑定IP,会报Failed to get advertise address: Multiple private IPs found. Please configure one.
的异常
-server
作用:指定节点为server
每个数据中心(DC)的server数推荐至少为1,至多为5
所有的server都采用raft一致性算法来确保事务的一致性和线性化,事务修改了集群的状态,且集群的状态保存在每一台server上保证可用性
server也是与其他DC交互的门面(gateway)
-client
作用:指定节点为client,指定客户端接口的绑定地址,包括:HTTP、DNS、RPC。默认127.0.0.1
,只允许回环接口访问;若不指定为-server,其实就是-client
-join
:将节点加入到集群
-datacenter
(老版本叫-dc,-dc已经失效):指定机器加入到哪一个数据中心中
consul catalog
用来接Consul目录进行交互:
- 列出数据中心:
consul catalog datacenters
- 列出节点:
consul catalog nodes
- 列出所有提供服务的节点:
consul catalog nodes -service=redis
- 列出所有服务器:
consul catalog services
consul event
event提供一种将自定义用户事件触发到整个数据中心的机制,这些事件对Consul是不透明的,但它们可用于构建脚本基础架构,以进行自动部署,重新启动服务或执行任何其他编排操作。Event可以通过使用watch来处理。event的传播是通过流言传播协议的。
consul info
info命令提供对运算符有用的各种调试信息。根据代理是客户端还是服务器,将返回不同的子系统信息。目前有几个顶级的键:
- agent:提供有关agent的信息
- consul:有关Consul的信息,包括客户端、服务端
- raft:提供有关Raft公共信息
serf_lan
:提供有关LAN流言池的信息serf_wandf
:提供有关WAN流言池的信息
consul join
join命令让Consul代理加入一个现有集群,新的Consul代理必须与集群的至少一个现有成员共同参与现有的集群。加入该成员后,流言层接管,跨集群传播更新成员的资格状态。如果没有加入现有的集群,则代理是自己的孤立集群的一部分,其他节点可以加入。代理可以加入其它的代理。如果已经是集群的一部分的节点加入另一个节点,则两个节点的集群将加入成为一个集群。
consul member
menber命令输出Consul代理人知道的当前成员名单及其状态。节点的状态只能是alive,left或failed。
consul lock
lock命令提供简单分布式锁定的机制。在KV存储中的给定前缀创建锁(或信号量),只有当被保持时,才会调用子进程。如果锁丢失或通信中断,则子进程终止。锁定器的数量可以使用-n标志进行配置。默认情况下,允许单个持有人,并且使用锁来进行互斥。这使用leader选举算法。
consul keygen
用于生成Consul代理流量加密的加密秘钥。
consul keyring
用于检查和修改Consul的流言池中使用的加密密钥。
consul monitor
monitor命令用于连接和跟踪正在运行的Consul代理的日志。Monitor将显示最近的日志,然后继续遵循日志,不会退出直到中断或直到远程代理退出。
consul reload
reload命令触发代理程序重新加载配置文件。
consul snapshot
snapshot命令具有用于保存,恢复和检查Consul服务器的状态用于容灾恢复的子命令。这些是原子的时间点快照,其中包括键值条目,服务目录,准备好的查询,会话和ACL。
实战
Java Client
前面已经在Mac/Linux系统下采用单机模式成功安装Consul Server,也能通过命令行与Server通信,并介绍Consul提供的若干个命令。
但是在Java开发中,需要使用代码的方式来实现。参考官网libraries-and-sdks,对于Java开发来说,可供选择的客户端有两个:
- rickfast开源的consul-client,GitHub仓库显示已经是archived只读状态,仅242个Fork,572个Star,对应的Maven依赖如下,最后发布时间为2021.07.04
<dependency><groupId>com.orbitz.consul</groupId><artifactId>consul-client</artifactId><version>1.5.3</version>
</dependency>
- Ecwid开源的consul-api,仅177个Fork,416个Star,对应的Maven依赖如下,最后发布时间为2020.04.09:
<dependency><groupId>com.ecwid.consul</groupId><artifactId>consul-api</artifactId><version>1.4.5</version>
</dependency>
Spring Cloud封装提供的spring-cloud-starter-consul-discovery
使用的是后者。
简单实例:
ConsulRawClient client = new ConsulRawClient("localhost", 8500);
ConsulClient consul = new ConsulClient(client);
// 获取所有服务
Map map = consul.getAgentServices().getValue();
一个疑问:Consul Server一直在持续迭代和发布新版本,官网推荐的两个Java Client都已经处于停止开发状态,后续该选择什么Client?
注册中心
引入依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
自动配置类ConsulAutoConfiguration,配置类文件ConsulDiscoveryProperties,配置文件:
server:port: 8023
spring:application:name: order-providercloud:consul:host: 127.0.0.1port: 8500discovery:register: trueserviceName: ${spring.application.name}preferIpAddress: trueregister-health-check: truehealth-check-path: /actuator/healthhealth-check-interval: 10shealth-check-timeout: 10shealth-check-critical-timeout: 30s #健康检查失败多长时间后,取消注册health-check-tls-skip-verify: trueinstance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
spring.cloud.client.ip-address
是系统自带的变量。
问题
使用Consul作为注册中心遇到的问题:
oauth-dx-provider | [http-nio-8848-exec-9] | | ERROR | o.s.c.client.discovery.health.DiscoveryClientHealthIndicator | health | 73 | - Error
com.ecwid.consul.v1.OperationException: OperationException(statusCode=500, statusMessage='Internal Server Error', statusContent='rpc error making call: No cluster leader')
at com.ecwid.consul.v1.catalog.CatalogConsulClient.getCatalogServices(CatalogConsulClient.java:128)
at com.ecwid.consul.v1.catalog.CatalogConsulClient.getCatalogServices(CatalogConsulClient.java:114)
at com.ecwid.consul.v1.ConsulClient.getCatalogServices(ConsulClient.java:367)
参考stackoverflow,问题的根源在于运维操作不当,后来自动恢复。深层次原因,限于能力有限,没能进一步深入分析挖掘。
配置中心
Consul支持键值对的存储,可以用来做分布式配置中心。Spring Cloud Consul Config依赖去和Consul相集成。
进阶
能力和篇幅有限,仅仅只是提及或列出Consul的一些高级概念和知识点,作为后续深入学习的一个引子。
持久化
Consul支持的KV存储的value值不能超过512KB;在dev模式启动下,所有数据都存储在内存中,Consul重启后会导致所有数据丢失;使用非dev模式启动时,Consul的数据会持久化,数据不会丢失。
ACL
加密
高可用
Anti-Entropy
反熵,熵是系统变得越来越无序的趋势。Consul的反熵机制旨在对抗这种趋势,即使在组件发生故障的情况下也能保持集群的有序状态。
Gossip协议
Consul使用Gossip协议来管理成员和集群广播消息,这些都是通过使用Serf库的。Serf所使用的Gossip协议基于SWIM,可伸缩的弱一致的感染模式的过程组成员协议,并加以细微的修改。
Consul使用两个不同的Gossip池,称为LAN池和WAN池。每个数据中心都有一个LAN池,其中包含数据中心的所有成员,包括服务器端和客户端。LAN的成员客户端可以自动发现服务器,减少所需配置的数量。分布式故障检测可以让故障检测的工具被整个集群共享,Gossip池可以快速可靠的将事件广播,比如选择Leader。
WAN池是全局唯一的,所有的服务器都应该在WAN池中,而不关系数据中心在哪里。WAN池提供的成员信息允许服务器执行跨数据中心请求。集成的故障检测功能使Consul能够优雅地处理整个数据中心或者远程数据中心的一个服务器失连。
Lifeguard Enhancement
在分组软实时处理可能的情况下,SWIN假设本地节点是健康的。但在本地节点遇到CPU或者网络节点资源匮乏的时候,可能不会认为节点不健康。结果是安全检测状态可能会偶尔瘫痪,导致虚假报警。Lifeguard解决这个问题。
Consensus协议
Consul通过Consensus协议来提供一致性(由CAP定义)。Consensus协议是基于Raft一致性算法。
Raft是一种基于Paxos的一致性算法。与Paxos相比,Raft被设计成更少的状态和更简单、更易于理解的算法。
Raft节点有三种状态:Follower,Candidate,Leader。所有的节点初始被置于Follower,在这个状态下的节点都可以收到来自Leader的Log并反馈。如果在一段时间没有收到任何信息,则会变成Candidate状态。在Candidate状态下,一个节点向其他节点发送请求,这个节点就成为Leader。Leader必须接收新Log并复制其到其他Follower那里。只有Leader才能进行读取Log。
集群一旦产生Leader,就可接受新的Log条目,客户端可请求Leader附加新的Log条目。这个Leader随后将Log条目写入持久存储,并复制到Follower。一旦Log条目被认为已经提交,它就会被用于有限状态机。有限状态机是相对于特定应用的,对于Consul而言,使用MenDB来维护集群状态。
显然,不需要无限制的复制日志。Raft提供一种机制,通过这种机制,让状态被记录时这个Log就会被压缩。
MenDB
Japsen测试
Serf
Spring Cloud封装的SerfStatusEnum枚举类有四个状态:
- StatusAlive
- StatusLeaving
- StatusLeft
- StatusFailed
服务网格Connect
对比
Consul与Eureka比较
Eureka是Netflix公司开源的服务注册中心组件。
在Eureka的架构体系中,分为Eureka服务端和Eureka客户端。Eureka服务端可以支持多数据中心,每个数据中心有一组Eureka服务端。通常,Eureka客户端使用嵌入式SDK来注册和发现服务。
Eureka使用注册列表复制的方式提供弱一致的服务视图。当Eureka客户端向Eureka服务端注册时,该Eureka服务端将尝试复制到其他Eureka服务端,但不提供强一致性保证。服务注册成功后,要求Eureka客户端对Eureka服务端进行心跳健康检测。不健康的服务或节点将停止心跳,从而导致它们的监控检查超时,并从注册表中删除。服务注册的请求可以路由到任何Eureka服务端,Eureka服务端可以提供过时或丢失的数据。这种简化的模型能够轻松地搭建Eureka服务端集群的高可用和强扩展性。
相比Eureka,Consul提供更多高级功能,包括更丰富的运行时健康检查、键值存储和多数据中心的相互感知。Consul提供强一致性的保证,因为Consul服务端使用Raft协议进行状态的复制。Consul支持丰富的运行时健康检查,包括TCP、HTTP、Nagios、Sensu兼容脚本等。Consul客户端基于Gossip的健康检查。服务注册请求会被路由到Consul领导者的节点。
Consul的强一致性意味着它需要用领导者选举和集群协调来锁定服务。Eureka采用的是P2P的复制模式,不保证复制操作一定能成功;Eureka不提供强制性的保证,而是提供一个最终一致性的服务实例视图。Eureka客户端在Eureka服务端的注册信息有一个带期限的服务续约,一旦Eureka服务端在指定时间内没有收到Eureka客户端发送的心跳,则Eureka服务端会认定Eureka客户端注册的服务是不健康的,将会其从注册表中删除定时任务。Consul与Eureka不同的是,Consul采用Raft算法,可以提供强一致性的保证,Consul的代理(Agent)相当于Netflix Ribbon + Netflix Eureka客户端,而且对应用来说相对透明。同时,相比Eureka这种集中式的心跳检测机制,Consul的代理可以参与到基于Goosip协议的健康检查中,分散服务端的心跳检测压力。Consul为多数据中心提供开箱即用的原生支持。