目录

一、架构

Consul是一个有很多模块的复杂系统,为了帮助Consul的开发者更好的理解它的运行模型。本章主要介绍Consul的架构。

1.1 术语

*
Agent:Agent是Consul集群中的守护进程。它的生命周期从启动Consul
agent开始。Agent可以以client或是server模式运行。由于所有的节点必须运行一个agent,将节点直接以client或是server形式引用更为简单,但是还会有其他agent实例?。所有的agent都有DNS或是HTTP接口,它们负责执行check并同步service信息。

*
Client:Client是转发所有RPC请求道Server的Agent。Client相对来说是无状态的,它的唯一后台活动是参与LAN gossip
pool。它的资源开销很小,只消耗少量的网络带宽。

*
Server:Server是负责参与Raft quorum,维护集群状态,响应RPC查询,和其他datacenter交换WAN
gossip信息并转发查询到leader或是远程datacenter的Agent。

*
Datacenter:datacenter的定义比较一目了然。必须考虑一些微妙的细节。例如,在EC2中,多个可用性区域被认为是由一个数据中心组成的吗?
我们将数据中心定义为私有、低延迟和高带宽的网络环境。这排除了穿越公共internet的通信,但是出于我们的目的,在单个EC2区域内的多个可用性区域将被视为单个数据中心的一部分。

*

Consensus:在我们的文档,我们使用Consensus共识来代表对应于leader选举和事务顺序的一致协议。由于事务应用于有限状态机,我们对于consensus的定义也以为这复制状态机的一致性。

*
Gossip:Consul是建立在处于多种目的提供了完整gossip
协议的Serf之上的。Serf提供了成员管理、错误检测、时间传播等特性。我们只需要知道gossip会触发随机的点到点通信,主要基于UDP协议。

*
LAN Gossip:位于相同本地网络区域或是datacenter的节点之间的LAN gossip pool。

*
WAN Gossip:只包含server的WAN gossip
pool。这些server主要存在于不同的datacenter中,并且通常通过internet或广域网进行通信。

*
RPC:Remote Procedure Call。这是一个请求/响应机制,允许client向server发送请求。

1.2 架构图



二、Consensus Protocol

Consul使用Consensus protocol提供一致性。Consensus protocol是基于Raft算法的。

2.1 Raft 协议概览

Raft是一种基于Paxos的一致性算法。和Paxos相比,Raft的状态更少,算法更简单易懂。

在讨论Raft时,有一些关键术语需要了解一下:

*
Log:Raft系统中的主要工作单元是一个log
entry。一致性的问题可以分解为日志备份。log是一个有序的条目序列。如果所有的成员对条目内容和顺序意见一致,那我们就认为日志是一致的。

*

FSM:有限状态机。FSM是有限状态和它们之间的转换的集合。在应用新日志时,允许FSM在状态之间进行转换。相同日志序列的应用必须导致相同的状态,意味着行为必须是确定的。

*
Peer set:对等集合是参与日志复制的所有成员的集合。在Consul中,所有服务器节点都位于本地数据中心的对等集。

*
Quorum:Quorum是一个Peer
set中的主要成员:对于一个大小为n的集合,Quorum要求至少有(n/2)+1个成员。例如,对等集合中有5个成员,我们需要3个节点来组成一个Quorum。如果一个Quorum中的节点处于某种原因不可用,name这个集群会不可用,无法提交新日志。

*
Committed Entry:当一个条目被持久地存储在节点的Quorum中时,它被认为是已经提交的。一旦提交了条目,就可以使用它。

*
Leader:在任何时刻,Peer
set都会选举出一个节点来作为leader。leader负责摄取新的日志条目,复制到追随者,并管理当一个条目被认为是提交的时候。

Raft中的节点总是处于以下三种状态之一:
follower、candidate或leader。所有的节点最初都是follower。在这种状态下,节点可以接受来自leader的日志条目并进行投票。如果在一段时间内没有收到条目,节点将自动提升到候选状态。在候选状态中,节点请求同级的选票。如果一个候选人获得了法定人数的选票,那么他就被提升为领袖。领导者必须接受新的日志条目,并将其复制给所有其他的追随者。此外,如果不能接受过时的读取,则还必须对leader执行所有查询。

2.2 Consul中的Raft

Consul中只有server节点会参与Raft算法并且作为peer
set中的一部分。所有的client节点会转发请求道server节点。这个设计的部分原因是,随着更多的成员被添加到对等集,quorum的大小也会增加。这将带来性能问题,因为您可能需要等待数百台机器对条目达成一致,而不是等待少数机器。

当启动时,单个Consul
server的模式为bootstrap。这个模式允许节点选举自身作为leader。一旦leader选举成功,其他服务器可以以保持一致性和安全性的方式添加到对等集。最终,一旦初始的部分server被加入,bootstrap模式就会被disable。


由于所有的server都处于对等集合中,它们都知道当前的leader是谁。当RPC到到一个非leader的server上时,请求会被转发到leader。如果PRC是一个查询类型,即只读的请求,leader会根据FSM的当前状态生成结果。如果RPC是一个转换类型,即它修改了状态,leader会生成一个新的日志条目并使用Raft算法对它进行应用。一旦日志条目提交并且应用于FSM了,转换请求就完成了。


由于Raft的备份特性,它的性能对网络延迟是很敏感的。出于这个原因,每一个datacenter会选举独立的leader并且维护自己的不相交的对等集合。数据被datacenter进行分区,所以每个leader只负责处理它自己datacenter的数据。当请求被一个远程datacenter接收时,会被转发到正确的leader。这种设计允许低延迟事务和高可用性,而不牺牲一致性。

2.3 一致性模型

虽然所有对复制日志的写入都要经过Raft,但是读取更灵活。为了支持开发人员可能需要的各种权衡,领事支持三种不同的读取一致性模式

*

default:Raft利用了leader租期,提供了一个时间窗口,在窗口中leader假设它的角色是稳定的。但是,如果一个leader与其他的对等节点隔离,一个新的leader可以在旧的leader持有租约的时候被选出。这意味着有两个领导节点。由于旧的领导不能提交新的日志,所以不会有脑裂的风险。但是,如果旧的leader处理任何读取,那么这些值可能会过时。默认的一致性模式只依赖于leader
租期,将客户暴露给潜在的陈旧值。我们之所以做出这种取舍,是因为读取速度很快,通常具有很强的一致性,并且在难以触发的情况下才会变得陈旧。陈旧读取的时间窗口也是有限制的,因为由于分区的原因,leader将会下台。

*

consistent:这个模式是强一致性的。它leader验证quorum来确保它仍然是一个leader。这将引入对所有服务器节点的额外往返开销。交换总是一致的读取,但是由于额外的往返,延迟增加了。

*

stale:这个模式允许所有的server处理读取请求,不管它是不是leader。这意味着读取操作可以是过时的,但通常是落后leader数据的50毫秒之内。交换是非常快速和可伸缩的读取,但是具有陈旧的值。这种模式允许读取没有一个leader,意味着一个不可用的集群仍然能够响应。

这三种模式可以在HTTP API的参数中指定。

2.4 部署表

下面的表显示了不同集群大小的仲裁大小和容错。推荐的部署是3或5台服务器。由于在故障场景中数据丢失是不可避免的,所以强烈建议不要进行单个服务器部署。



 

三、Gossip Protocol

Consul使用gossip protocol来管理成员以及在集群中广播消息。所有的这些功能都是由Serf library提供的。

3.1 Gossip in Consul

Consul使用了两种不同的gossip 协议,我们称之为LAN gossip 协议和WAN gossip
协议。在每个datacenter中Consul执行LAN gossip pool,包括client和server。LAN
pool的目的较少。主要是用来允许client法相server,减少配置数量。分布式故障检测允许整个集群共享故障检测工作,而不是集中在几个服务器上。最后,gossip
pool允许可靠而快速的事件广播,如leader选举。

WAN Gossip pool是全局唯一的,所有的跨Datacenter的server都会参与到WAN Gossip pool中。WAN
pool允许成员跨datacenter请求。

这些特性都是由Serf提供的,用户无需感知。

 

3.2 Lifeguard Enhancements


SWIM(???)假设所有的本地节点都是健康的,以此来对数据包进行软实时处理。然而,当本地节点出现CPU或是网络耗尽的情况下,这一假设就会被推翻。结果是,serfHealth的检查状态会出现故障,导致错误的监控报警,向远程遥测添加噪声,导致集群浪费CPU和网络资源,诊断并不实际存在的噪声。

Lifeguard通过增加SWIM解决了这一问题。用户无需感知。

 

四、网络坐标


Consul使用网络断层扫描系统来计算就去哪中节点的网络坐标,这些坐标允许使用一种非常简单的计算方式来估计两点节点之间的往返时长。这可以为许多有用的功能提供服务,例如找到距离请求节点最近的service节点,或是向最近的datacenter进行故障转移。

所有这些功能都是Serf library提供的实现。

4.1 Consul中的网络坐标

Consul中的网络坐标的功能体现在以下几点

*
Consul rtt命令可以查询两个节点之间的网络往返时间

*
Catalog和Health端点可以接收?near=的参数,基于网络往返时间对查询结果进行排序

*
Prepared queries可以基于网络往返时间自动故障转移到其他Consul datacenter

*
Coordinate端点暴露原始的网络坐标给应用

五、Sessions

Consul为分布式锁提供了一种Session机制。Session在节点、健康检查和KV存储中作为绑定层存在。它的设计目的是提供细粒度的锁,它的设计启发来源于
http://research.google.com/archive/chubby.html
<http://research.google.com/archive/chubby.html>

5.1 Session设计


Consul中的Session具有一个有指定语义的规范。当session创建时,可能会提供节点名称,健康检查集合,行为,TTL和锁延迟信息。新创建的session有一个可用于标识它的命名ID,这个ID可以用于KV存储来获取锁
:排除互斥锁的咨询机制。

下图是这些组件之间的关系



当出现下面的场景时,session将会失效:

*
Node注销

*
任意一个健康检查注销

*
任意一个健康检查状态变更为critical

*
session被显式注销

*
TTL过期


session无效后,会被注销并不再使用。它关联的锁的状态依赖于session创建时指定的行为。Consul支持release和delete行为,release行为是默认的。


如果指定了release行为,那么这个session关联的所有锁都会被释放,并且key的ModifyIndex会自增。另外,如果使用了delete行为,锁对应的key会被直接删除。

虽然session的设计模式较为简单,但是它可以支持多种使用模式。主要的三种使用场景如下:

*

默认情况下,基于gossip的故障检测器用于执行健康监测。故障检测器允许Consul监测持有锁的节点何时失败,并自动释放锁。这种能力为Consul的锁提供了活性,即,在失败的情况下,系统可以继续运行。然而,由于没有完美的故障检测器,所以可能会发生监测错误,即锁的所有者仍然活着,但是锁被释放了。这意味着我们会牺牲一些安全性。

2.
相反,我们可以创建一些和健康检查无关的session。这就消除了假阳性的可能性,并以活力换取安全性。你绝对可以肯定Consul不会释放锁,即使现有的锁所有者已经失败。由于Consul
api允许强制销毁会话,因此可以构建系统,在发生故障时需要操作员进行干预,同时防止发生裂脑。

3. 第三种健康检查的机制是设置session
TTL。当创建一个session是,可以指定一个TTL。如果TTL超过间隔时间还未更新,那么session就会过期并触发失效。这种类型的故障检测也称为心跳检测。它的扩展性不如基于gossip协议的故障检测,因为它增加了server的负载,但是在某些情况是适用的。TTL的规则代表了一个失效的底线,即,Consul在TTL时间到达之前让session失效,但是允许将失效延迟到TTL过期之后。TTL在session创建、刷新和leader故障转移的时候被刷新。当使用TTL时,client必须注意时钟偏差问题,即,client和Consul
server上的时钟可能会有差异。考虑到网络延迟和时间倾斜,最好设置保守的TTL值,并在TTL到期之前进行更新。


最后关于session的细微差别是所延迟,这是一个时间段,在0到60s之间。当会话失效时,Consul会阻止任意的前锁持有者在锁延迟间隔里重新获取锁。这是一个受Google
Chubby启发的保护策略。延迟的目的在于允许仍然存活的leader检测到失效并停止处理可能导致不一致状态的请求。虽然它不是一种非常可靠的办法,但是它
能避免将睡眠状态引入应用程序的必要。并且可以帮助缓解许多问题。默认情况下延迟时间为15s,client可以提供一个值为0的延迟值来禁用此机制。

5.2 KV集成

KV存储和session的集成是session的主要使用场景。session必须在使用之前创建,然后通过它的ID来进行引用。

KV
API扩展支持了acquire和release操作。acquire操作的运作方式类似Check-And-Set操作,但它只能在没有锁持有者的情况下才能成功(当前锁持有者可以re-acquire)。一旦成功,就执行正常的key
update操作,但是仍然会增加LockIndex,并且Session value会更新以反映持有锁的session。


如果锁已经在一次acquire过程中被给定session持有了,LockIndex不会增加但是key的内容会被更新。这是的当前锁持有者可以在无需放弃锁并重新获取的情况下直接更新key内容。


一旦持有,锁可以通过同一个session提供的release操作来进行释放。同样,这个行为也类似Check-And-Set操作因为如果session是无效的请求会失败。一个重要的注意点是并不是只有session的创建人才能释放锁。这样的设计方式允许在必要情况下强制终止会话。如上面所提到的,一个session的失效会导致该session所有持有的锁被释放或是删除。当一个锁被释放,LockIndex不会在变更,然而,此时session已经被清除了并且ModifyIndex值自增了。


这些语义(从Chubby大量借用),允许(Key,LockIndex,Session)的元组作为一个独立的sequencer存在。sequencer可以被传递,用来验证请求是否来源于正确的锁持有者。由于LockIndex值在每次acquire操作之后自增,尽管同样的session会re-acquire同一个锁,这个sequencer还是可以检测出过时的请求。同样的,如果session失效,给定的LockIndex对应的会话将为空。


需要说明的是,这个locking系统完全是建议性的。没有强制要求客户端必须获取锁来执行任何操作。任何客户机都可以读取、写入和删除密钥,而无需拥有相应的锁。Consul的目的不是为了避免错误操作的client带来的影响。

5.3 Leader选举

Session和KV存储的锁机制所提供的原子操作可以用来建立client短的leader选举算法。具体内容参考
https://www.consul.io/docs/guides/leader-election.html
<https://www.consul.io/docs/guides/leader-election.html>

5.4 Prepared Query 集成

Prepared queries可以附加到Session中以在session失效是自动删除Prepared queries。

六、反熵Anti-Entropy


Consul使用了一个先进的方法来维护服务和健康信息。本章详细描述了服务和check的注册方式,catalog是如何填充的,以及健康检查状态信息是如何被变动触发更新的。

6.1 组件

首先,了解service和health
check中的移动组成部分是非常重要的:agent和catalog。为了使反熵更容易理解,下面对它们进行了概念性的描述。

6.1.1 Agent

每一个Consul agent都维护它自己的service集合和check注册以及health信息。agent负责执行它们自己的健康检查并更新自己的本地状态。

Agent中的Service和Check都具有丰富的配置化参数。这是因为agent负责通过health
check来生成它的service和service的健康检查的信息。

6.1.2 Catalog

Consul的服务发现是由一个serice
catalog支持的。这个catalog是由这个agent提交的信息聚合而成的。catalog维护集群的high-level
视图,包括哪个服务是可用的,哪些节点运行了哪些服务,健康检查信息等等。catalog通过Consul提供的多种接口包括DNS和HTTP向外暴露这些信息。

Catalog中的Service和Check和Agent相比具有更有限的字段集合。这是因为catalog只负责记录和返回关于服务、节点和health的信息。

Catalog是由server节点维护的,这是因为Catalog是通过Raft log备份的,用来提供关于集群的统一和一致的视图。

6.2 Anti-Entropy


熵Entropy是使系统越来越无序的趋势。Consul的反熵机制Anti-Entropy是设计用来对抗这一趋势的,用来在即使有组件失败的情况下保持集群状态的有序性。


Consul的全局服务Catalog和agent的本地状态是互相独立的。反熵机制对这两种视图进行了协调,反熵是一种对于本地agent状态和catalog之间的同步。例如,当用户在agent中注册了一个新的service或是check,agent会通知catalog这个新的check的存在性。同样的,当agent删除了一个check时,它同样也会被从catalog中删除。


同步过程同时还会检查catalog的正确性。如果catalog中存在agent未感知的任何服务或是check,他们会被自动从catalog中删掉来使catalog可以反映agent中正确的service和health信息集合。Consul以agent的信息为准,如果catalog和agent中的视图存在差异,会以agent本地的视图为准。

 

6.3 周期同步


Anti-Entropy机制除了在agent发生变化时运行还会作为一个长期运行的进程存在,会周期性的唤醒以同步service和check的状态到catalog中。这保证了catalog可以最大程度地和agent的真实状态匹配。Consul还允许在数据完全丢失的情况下充填service的catalog信息。

为了避免信息同步的饱和性,周期性运行的Anti-Entropy会基于集群的大小来进行调整。下表定义了集群大小和同步间隔之间的关系


Cluster Size

Periodic Sync Interval


1 - 128

1 minute


129 - 256

2 minutes


257 - 512

3 minutes


513 - 1024

4 minutes


...

...

 

6.4 最优同步

Anti-Entropy可能在一些场景下失败,包括agent的误配置、I/O故障,网络问题等等。因此,agent会尝试以最优方式同步。

如果一个Anti-Entropy运行过程中发生了错误,错误会被记录,agent继续运行。Anti-Entropy会周期性的尝试恢复故障类型。

6.5 标签覆盖

注册服务的同步可以被部分修改以允许agent去修改service的tag。例如Redis集群的master和slave标签。

七、安全模型

八、Jepsen测试

 

 

 

 

 

 

 

 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信