Consul作为注册中心在云环境的实践与应用
作者:互联网
前言
本文主要介绍Consul作为注册中心在『云』环境的实践与应用。开始本文介绍之前,首先会简单介绍注册中心基础知识以及相关理论,以便读者更好的理解,随后会重点介绍在『云』环境中使用Consul作为注册中心的实践经验。
注册中心介绍
在微服务架构流行之前,注册中心就已经出现在分布式架构的系统中,随着近些年微服务架构越来越受到开发者的青睐以及云原生理念逐步被开发者接受,注册中心作为微服务架构中最核心的基础设施之一,其重要性不言而喻。
什么是注册中心
在介绍什么是注册中心之前,我们先看一个现实中的例子,相信大家都是用过手机通讯录,我们以此为例:
- 当你想要给【同事A】打电话时,那么你首先在手机通讯录中找到【同事A】,然后通讯录【同事A】的名片中显示其对应的电话号码,可以通过拨打电话号码找到【同事A】;
- 当【同事A】更换了电话号码,并告诉你他的电话号码,你把电话号码保存进通讯录,后续你就可以通讯录方便查找到【同事A】电话号码了;
上述两个场景,其实跟微服务场景中的两个概念非常贴切:
- 服务发现:通过通讯录中【同事A】方便的查询到了其电话号码;
- 服务注册:我们把【同事A】的电话号码保存至通讯录中,方便后续基于【同事A】查询其电话号码;
相信大家都已经理解了这个现实场景,我们再对注册中心做以下说明,注册中心最本质的功能可以看成是一个函数:
# service-name服务名为查询参数,Result代表可用的 endpoints (ip:port) 列表为返回值
Result = F(service-name)
为什么需要注册中心我们还是以上面的例子为例,我相信在实际生活中应该不会有人会记住每个同事的电话号码,况且同事的电话号码可能会发生变化,因此通过这种方式会显得不切合实际,我们只需要记住同事的名字即可,通过同事的名字查询其对应电话号码。相信到这里读者已经发现为什么需要注册中心了。我们在回到分布式架构中,服务调用方只需要记住需要调用服务的逻辑名称即可,可以通过注册中心查询其逻辑名称对应的服务地址。在实际实践过程中还会发现很多问题,如下:
- 服务注册后,如何被及时发现;
- 服务宕机后,如何及时下线;
- 服务如何有效的水平扩展;
- 服务发现时,如何进行路由;
- 注册中心如何实现自身的高可用;
这里问题的解决都依赖于注册中心。简单看,注册中心的功能有点类似于DNS服务器或者负载均衡器,而实际上,注册中心作为微服务的基础组件,可能要更加复杂,也需要更多的灵活性和时效性。
主流注册中心
上面介绍了很多注册中心的基础知识,下面我们重点介绍下目前市面上的主流注册中心:
- Zookeeper:Yahoo公司开发的分布式协调系统,可用于注册中心,目前仍有很多公司使用其作为注册中心;
- Eureka:Netflix开源组件,可用于服务注册发现组件,被广大Spring Cloud开发者熟知;
- Consul: HashiCorp公司推出的产品,其可作为实现注册中心,也是本文介绍的重点;
- Etcd:Etcd官方将其定义为可靠的分布式KV存储;
.......
对于上述注册中心的各项对比,并不是本文的重点,相信各位读者都会根据各自的实际情况选择不同的注册中心,我们重点介绍Consul作为注册中心的实践与应用。
理论
分布式基础理论
相信很多熟悉分布式系统设计的读者都知道CAP理论,CAP理论告诉我们一个分布式系统不可能同时满足一致性(C: Consistency)、可用性(A: Availability)和分区容错性(P: Partition tolerance)。其中这三点主要描述了:
- 一致性:在分布式环境下,多个副本之间能够保持一致的特性,当系统在一致性条件下执行更新操作后,系统的数据还应保持一致性;
- 可用性:指的是系统提供的服务一直处于一个可用的状态;
- 分区容错性:指的是当分布式系统在遇到网络分区后,使得原有的分布式系统被隔离为孤立的区域,仍可以对外提供满足一致性和可用性的服务;
后来,又出现了BASE理论,BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致)三个短语的缩写,其中最终一致性指的是系统中的所有数据副本,在一段时间的同步后,最终能够达到一个一致的状态,因此最终一致性的本质是需要系统保证最终数据能够一致,而不是需要实时保证系统数据的强一致性。
一致性算法Raft
讲了这么多,我们主要为了引出分布式一致性算法。分布式一致性算法允许一组机器像一个整体一样工作,即使其中一些机器出现故障也能够继续工作。为了解决分布式一致性问题,在长期的探索研究中,涌现了一批经典的一致性协议和算法,其中比较著名的是两阶段提交协议、三阶段提交协议、Paxos、ZAB、Raft等。下面我们主要介绍Raft共识算法,其一开始就被设计成一个易于理解和实现的算法;Consul中也是使用Raft协议作为其一致性算法,其他一致性协议有兴趣的读者也可以查阅相关资料。为了提高可理解性,Raft将一致性算法分解为几个关键的模块,下面主要介绍两个重要模块:领导人选举(leader election)、日志复制(Log replication)。Raft一致性算法在许多方面和现在的一致性算法很相似,但是它有一些独特的特性:
- 强领导者(Strong Leader):和其他一致性算法比,Raft算法使用了一种更强的领导能力。比如日志条目(log entry)只从领导者发送给其他的server。这种方式简化了对复制日志的管理并且使Raft协议更加容易理解;
- 领导人选举(Leader election):Raft算法使用了一个随机计数器使得在选举领导者解决瓜分选票冲突时更加简单和快捷;
节点状态
Raft中规定的节点类型包括了:跟随者(Follower)、竞选者/参选者(Candidate)和领导者(Leader)。
图:节点状态变化,Follower仅响应其他节点的请求。当follower在一段时间内未接收到请求时,则会变为Candidate初始化一轮选举。当Candidate接收到集群中的半数以上节点的响应后则会变为leader。Leader执行处理逻辑直到它失败;
注 本图来源于论文《In Search of an Understandable Consensus Algorithm》Figure 4;
复制状态机(Replicated state machines)
一致性算法是从复制状态机的背景下提出的。在这种算法中,一组服务器上的状态机产生相同状态的副本,并且在一些机器宕掉的情况下也可以继续运行。
图 复制状态机的结构。一致性算法管理着来自客户端指令的复制日志。状态机从日志中处理相同顺序的相同指令,所以产生的结果也是相同的。注 本图来源于论文《In Search of an Understandable Consensus Algorithm》Figure 1复制状态机通常都是基于复制日志实现的,如上图。每一个服务器存储一个包含一系列指令的日志,并且按照日志的顺序进行执行。每一个日志都按照相同的顺序包含相同的指令,所以每一个服务器都执行相同的指令序列。因为每个状态机都是确定的,每一次执行操作都产生相同的状态和同样的序列。保证复制日志相同就是一致性算法的工作了。
领导选举(leader election)
初始Follower状态Raft使用一种心跳机制来触发领导人选举,当节点启动时,其状态都为follower。一个节点继续保持follower状态直到其能够从Leader或者Candidate处收到有效的RPC请求。Leader周期性的向所有的follower发送心跳包(Empty AppendEntry)来维持自己的权威性。如果一个跟随者在一段时间内没有接收到任何消息,这就是选举超时,它会认为系统中没有可用的leader,则会发起选举选出新的leader。Follower转换为Candidate状态一次选举过程,Follower需要先增加自己当前的任期号并且转换为Candidate。然后它并行的向集群中的其他节点发送请求投票(Request Vote)的RPC请求来给自己投票。Candidate继续保持该状态直到这三件事情之一发生:
- 自己赢得了这次选举(收到半数以上节点的投票);
- 其他节点成为了leader(其收到了leader的heartbeat);
- 一段时间内没有任何节点获胜(瓜分投票数);
Candiate转为Leader状态当一个Candidate从整个集群中大多数节点获取了针对同一任期号的投票,则它赢得这次选举并成为leader。每个节点最多能够对一个任期号投出一张选票,并且按照先来先服务的原则。针对平等瓜分选票(这也是集群选择奇数个节点的原因):Candidate既没有赢得选举也没有输:如果有多个Follower同时成为候选人,那么选票可能会被瓜分以至于没有Candidate可以赢得大多数人的支持。当这种情况发生的时候,每一个候选人都会超时,然后通过增加当前任期号来开始一轮新的选举。Raft 算法使用随机选举超时时间的方法来确保很少会发生选票瓜分的情况,就算发生也能很快的解决。每一个候选人在开始一次选举的时候会重置一个随机的选举超时时间,然后在超时时间内等待投票的结果,这样减少了在新的选举中出现选票瓜分的可能性。推荐读者可以参考动图了解该部分具体实现,这有助于读者更好的了解其实现:http://thesecretlivesofdata.com/raft/
日志复制(Log Replication)
图:日志复制
Raft 协议强依赖 Leader 节点来确保集群数据一致性,具体的处理流程:
- client 发送过来的数据(客户端的每一个请求都包含被复制状态机执行的指令)均先到达 Leader 节点(若到达follwer节点则转发至leader),Leader 接收到数据后,把该该指令作为新的日志条目添加到其日志中,先将数据标记为 uncommitted 状态;
- 随后 Leader 开始向所有 Follower 复制数据并等待响应,在获得集群中大于 N/2 个 Follower 的已成功接收数据完毕的响应后,Leader 将数据的状态标记为 committed,应用到状态机中;
- 随后向 client 发送数据已接收确认,
- 在向 client 发送出数据接收响应后,再向所有 Follower 节点发送通知表明该数据状态为committed。
Consul注册中心实践与应用
Consul介绍
Consul是HashiCorp推出的一款品,其是一个service mesh解决方案,提供了功能丰富的控制面功能:service discovery、configuration以及segmentation functionality。这些功能可以根据需要独立使用,或者将它们一起使用用来构建完整的service mesh。Consul提供的关键功能如下:
- Service Discovery:服务注册/发现功能,可以注册服务,也可以通过http或dns的方式发现已经注册的服务,这也是本文介绍的重点;
- Health Checking:健康检查,丰富的健康检查方式;
- KV Store: KV存储功能,其可实现多种多样的需求,如动态配置存储,分布式协调、leader选举等;
- Multi Datacenter: 多数据中心,Consul提供多数据中心功能,使用者无需使用额外的抽象层去构建多region场景;
更多详细内容,读者可参考:https://www.consul.io/intro/index.html架构设计如下图:
图:Consu架构设计;
为方便读者理解,对相关术语进行说明:
- Agent: Agent是运行的damon进程在Consul 集群的每个节点上,通过 consul agent将其启动,agent 可以运行在client或者server模式下。
- Client:Client是一种agent,其将会重定向所有的RPC 请求到Server。Client是无状态的,其主要参与LAN Gossip协议池。其占用很少的资源,并且消耗很少的网络带宽。
- Server:Server是一种agent,其包含了一系列的责任包括:参与Raft协议写半数(Raft Quorum)、维护集群状态、响应RPC响应、和其他Datacenter通过WAN gossip交换信息和重定向查询请求至leader或者远端Datacenter。
- Datacenter: Datacenter其是私有的、低延迟、高带宽的网络环境,去除了在公共网络上的网络交互。
- Consensus: Consensus一致性在leader 选举、顺序执行transaction 上。当这些事务已经提交至有限状态机(finite-state machine)中,Consul定义consensus作为复制状态机的一致性。本质上使用实现了Raft协议,对于具体实现细节可参考 Consensus Protocol。
- Gossip:Consul使用了Serf,其提供了Gossip协议多种用途,Serf提供成员关系、失败检查和事件广播。
- LAN Gossip: Local Area Network Gossip其包含在同一个网络环境或Datacenter的节点。
- WAN Gossip: Wide Area Network Gossip 其只包含Server节点,这些server分布在不同的datacenter中,其主要通过因特网或广域网相互交流。
- RPC: 远程过程调用。
Raft In Consul
- 只有Consul Server节点参与Raft相关功能(选主、日志复制),越多的server节点添加,会影响整个consul 集群的性能,建议是3-5个server节点;
- 当刚开始时,单个Consul Server节点可以以"bootstrap"模式启动,这种模式允许单个节点选为leader,后续其他节点可以加入该集群,此时bootstrap模式会失效(因为peer set被更新);
- 当所有的节点作为一部分参与Raft协议时,它们都知道目前的Leader。当请求到达非leader节点时,若该请求为write时,请求会被重定向到leader节点,leader产生log entry并且用Raft协议完成日志复制,当log entry被提交时并且应用到状态机时,该事务就完成了;
- 每个Datacenter都会选举一个独立的leader,每个leader只负责其对应的Datacenter的数据。当请求需要访问另外Datacenter时,该请求会被重定向到对应的Datacenter中;
更加详细说明请参考:参考:https://www.consul.io/docs/internals/consensus.html
实践与应用
介绍了这么多理论知识有助于我们理解后文的实践,接下来我们开始介绍其实践与应用;
架构设计
图:云环境架构设计;
注册中心作为基础组件,其自身的可用性显得尤为重要,高可用的设计需要对其进行分布式部署,同时因分布式环境下的复杂性,节点因各种原因都有可能发生故障,因此在分布式集群部署中,希望在部分节点故障时,集群依然能够正常对外服务。Consul使用Raft协议作为其分布式一致性协议,本身对故障节点有一定的容忍性,在单个DataCenter中Consul集群中节点的数量控制在2*n + 1个节点,其中n为可容忍的宕机个数。我们在设计时采用同Datacenter集群内部部署3个Server节点,来保障高可用性,当集群中1个节点发生故障后,集群仍然能够正常运行,同时这3个节点部署在不同的机房,达到机房容灾的能力。若读者对Raft协议中日志复制(Log Replication)熟悉则会更加轻松的理解对于该节点数量设计,读者也可参考Consul官网对部署的说明。在云上环境,涉及多region环境,因此在架构设计设计时,我们首先将Consul的一个Datacenter 对应云上一个region,这样更符合Consul对于Datecenter的定义(DataCenter数据中心是私有性、低延迟、高带宽的网络环境)。中间代理层(Proxy Layer):实现服务鉴权、多租户隔离等功能。
云原生实践
服务注册
服务注册接口
Method | Path | Produces |
---|
{
"ID": "instance-test-default-provider-demo-172-22-204-39-provider-demo-10001",
"Name": "provider-demo",
"Tags": [
""
],
"Address": "172.22.204.39",
"Port": 10001,
"Meta": { # 相关meta信息
"key1": "value1"
},
"Check": {
"TTL": "30s", # TTL健康检查
"deregisterCriticalServiceAfter": "30s" # 异常服务下线
}
}
- 其ID需要保证在Consul Agent上唯一,其中可加入租户id、隔离域、应用程序部署主机信息等;
- Meta可携带租户id等元数据;
健康检查
Consul提供多种多样的健康检查方式,可以分为:
- Script + Interval
- HTTP + Interval
- TCP + Interval
- Time to Live (TTL)
- Docker + Interval
- gRPC + Interval
- Alias
结合云上的实际情况,包括底层依赖和网络环境,采用Time To Live(TTL)方式作为服务健康检查方式,即由业务方应用定期向注册中心汇报状态,此处进行两点说明:
- 针对应用运行期间异常退出:针对未及时汇报健康状态的应用,注册中心会将其主动剔除;
- 针对短时间网络异常:云上网络环境复杂,往往一段时间内网络出现了故障,用户业务应用在网络故障期间无法和注册中心正常通讯(即无法正常心跳汇报其健康状态),注册中心会视它为不健康实例,会将其从注册中心中剔除,当网络环境恢复后,用户业务应用心跳正常,此时注册中心上已经不存在该数据,针对此种情况需要重新进行注册,保障在网络故障恢复后,服务数据能够重新注册至注册中心;
更多健康检查细节,读者可参考:https://www.consul.io/docs/agent/checks.html
多租户
云上环境存在多租户隔离的需求,即:
- A租户的服务只能发现A租户服务的实例;
针对此场景,需要在 『中间代理层』完成对多租户隔离功能的实现,其主要实践思路为,使用Consul Api Feature 具备 Filtering功能:
- 利用Filtering功能实现租户隔离需求;
- 减少查询注册中心接口时网络负载;
利用Filtering特性,可以自定义Filtering表达式,可实现绝大多数的逻辑运算,因此在实践过程中,服务注册时,会将租户信息存储在Meta信息中,查询时采用该信息实现Filtering 表达式,具体的例子如下所示:
$ curl -G http://localhost:8500/v1/agent/services --data-urlencode 'filter=Meta.tenant==test'
更多Filtering细节,读者可参考:https://www.consul.io/api/features/filtering.html
鉴权认证
在实际的应用场景,我们需要保证数据的安全性,主要的要求我们可以总结为2点:
- 对于注册中心,租户A不能发现租户B的服务注册信息,所有相关请求在经过平台级别安全认证后统一在 中间代理层Proxy Layer 做到租户隔离;
- 对于配置中心(Consul KV存储),租户A不能查看租户B的配置信息,Consul KV存储是存在路径的,因此租户id可以作为路径中一部分,因此基于Consul ACL System可以设置对应的Policy 如下:
key_prefix "test" {
policy = "read"
}
数据同步
图:跨Datacenter(Region)数据同步;
在实际的实践的过程中,我们发现需要跨Datacenter的场景会分为以下几个方面:
- 跨Datacenter完成ACL(Access Control List 访问控制列表)数据同步,即在一个Datacenter中申请的ACL数据,可以在其他Datacenter中正常使用,本身可减少用户在不同的Datacenter中申请ACL数据,Consul支持跨Datacetner的ACL数据同步;
- 跨Datacenter完成配置KV数据同步,即在一个Datacenter中写入的KV数据可以同步至其他Datacenter中,其主要利用了Consul官方提供的Consul Replicate工具来实现跨Datacenter的KV数据同步;
容灾
注册中心作为微服务基础设施,因此对其容灾和其健壮性有一定的要求,主要体现在:
- 注册中心作为微服务基础设施,因此要求出现某些故障(如节点挂掉、网络分区)后注册中心仍然能够正常运行;
- 当注册中心的发生故障时,不能影响服务间的正常调用;
服务端容灾
图:Datacenter设计;
Consul使用Raft协议作为其分布式一致性协议,本身对故障节点有一定的容忍性,在单个DataCenter中Consul集群中节点的数量控制在2*n + 1个节点,其中n为可容忍的宕机个数。Consul官网对每个Datacenter集群中可容忍的故障节点个数进行了说明:
Servers数量 | Quorum Size(半数节点) | Failure Tolerance(可容忍故障数) |
---|
基于上述表格中可容忍的故障数同时结合实际的场景需求,设计在Datacenter中部署3个Consul Server节点。可能有读者有疑问:Q1: 节点的个数是否可以为偶数个? 答案是 可以的,但是不建议部署偶数个节点,一方面如上表中偶数节点4和奇数节点3可容忍的故障数是一样的,另一方面,偶数个节点在选主节点的时候可能会出现 瓜分选票的情形(虽然Consul通过重置election timeout来重新选举),但是还是建议选取奇数个节点。Q2: 是不是Server节点个数越多越好? 答案是 否定的,虽然上表中显示Server数量越多可容忍的故障数越多,熟悉Raft协议的读者肯定熟悉 Log Replication如上文介绍(日志复制时过半写成功才返回写成功),随着Server的数量越来越多,性能就会越低,所以结合实际场景一般建议Server部署3个节点。 若读者对Consul中的Consensus有兴趣,可参考:https://www.consul.io/docs/internals/consensus.htm
客户端容灾
图:客户端容灾;
注册中心设计的一个重要前提是:注册中心不能因为自身的原因或故障影响服务之间的相互调用。因此在实践过程中,如果注册中心本身发生了宕机故障/不可用,绝对不能影响服务之间的调用。这要求对接注册中心的SDK针对这种特殊情况进行客户端容灾设计,『客户端缓存』就是一种行之有效的手段。当注册中心发生故障无法提供服务时,服务本身并不会更新本地客户端缓存,利用其已经缓存的服务列表信息,正常完成服务间调用。
讲到这里,本文的整体内容就已经讲述完了,文中很多知识点只是进行了简单介绍,更深入的还需读者可进一步查阅相关资料,望本文能够让读者对 Consul作为注册中心及其实践有进一步认识和理解。
附录
- raft共识算法介绍:https://raft.github.io/
- 《In Search of an Understandable Consensus Algorithm》:https://raft.github.io/raft.pdf
- Raft动画:http://thesecretlivesofdata.com/raft/
- Raft交互式动画:https://raft.github.io/raftscope/index.html
了解更多微服务、云原生技术的相关信息,请关注我们的微信公众号【云原生计算】!
标签:Datacenter,Consul,实践,注册,一致性,Raft,节点 来源: https://blog.csdn.net/yunyuansheng/article/details/113517682