Raft协议

Posted 向V的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Raft协议相关的知识,希望对你有一定的参考价值。


分布式领域CAP理论说明了一致性,可用性,分区容错性只可同时满足两个,不可能同时满足。这篇我们讲讲一致性协议的一个实现:Raft一致性协议。一致性算法允许相关联的一组机器在少量成员出现错误(机器宕机等)的情况下依然保证工作。比较著名的一致性算法是Paxos,但是Paxos是一种负责的算法,据说当时没有几个人能理解,而且作者本身也没有从算法层面进行证明,作者只是进行了阐述,直到20实际90年代Paxos作者才重新发表论文证明Paxos算法的正确性。Raft也是一种一致性算法,算法保证了跟Paxos一样的结果,但是相比Paxos更容易理解,因此Raft算法更方便实现。

Raft基础概念

Raft协议中节点的状态分三种:

Leader:集群的主,写入和读取都从leader上进行,定期向其他节点发送心跳。

Candidate:候选人,选主过程中的状态,一个节点可以从Candidate成为leader,也可以成为follower

Follower:从节点,接受Leader的日志复制请求,更新自己的状态机。

Rafe协议的机制从另一个角度来看,将连续的时间分成了任意长度的周期(term),每个周期的标识是连续递增的term_id。每个周期的开始阶段是Leader elect,当leader被选出,这个周期内所有的client请求由leader处理。Term的概念在raft中是一个逻辑时钟,让节点可以识别过时的信息(比如过时的leader)。每个几点都保存了一个当前term的变量,这个变量在每一次通信中相互交换确认,一个follower收到新的term,则更新自己的termcandidate或者leader发现自己term陈旧,则转换到follower状态;一个节点收到比自己term旧的term请求,则拒绝响应。

term示意

Leader在一个固定时间内向所有follower发送心跳请求,或者向follower发送日志复制请求,follower被动响应leader的请求。Follower也有一个定时器,定时结束前没有收到心跳或者日志复制请求,follower状态转换为candidate,发起新的leader elect过程,向其他节点发送投票请求。Candidate收到大多数节点的同意则转换为leader状态。如果在一个时间内candidate没有收到大多数节点的回应则重新发起选举过程。

当一个节点处于Leader状态时,它处理所有的client请求,直到发现有节点处于比自己的term_id更新的term,自己转换成follower


图2 节点状态转换

 

选主过程

Raft使用心跳机制触发选主过程。节点起始状态为follower,在一个时间(election timeout)内收到leader或者candidate请求,将保持follower状态,若在此时间内没有收到其他请求,此节点将认为没有leader,发起选举过程。

发起选主过程的节点首先增加自己的term,并装换成candidate状态,并行向集群其他节点发送投票请求。节点的candidate状态将一直持续直到以下三种请况出现(a)自己赢得选举(b)另一个节点声称自己是leadercelection timeout后没有成为leader

candidate得到大多数的投票后成为leader。集群中的每个节点在一个term内只会投票给一个candidate(先到先得原则, 为了保证安全性投票的另一个原则是candidateterm比自己的大,并且比自己已经投过的term大)。在等待投票过程中,如果收到其他请求,并且请求的term至少和自己的term一样大,将自己转换成follower

Raft使用随机时间长度(大概150-300ms)作为election timeout,使用随机的时间值保证大部分情况下只有一个节点发起选主过程。

日志复制

当成为了leader之后,节点开始回应client的请求(command)。Leader首先将command append到自己的log中,然后并行向其他节点发送AppendEntries请求。如果大多数的节点返回成功,leader将上个log commit。如果follower失败了(follower宕机, 网络丢包等),leader会一直尝试直到该follower成功。

每个Log Entry包含一个状态机命令以及term号,每个log entry还有一个index标识自己的位置。Leader决定什么时候commit一个log entry是安全的,Raft保证了commited log entry是不变的,并且最终会被所有的follower执行。

Leader跟踪所有follower下一个commit logindexleaderAppendEntries总是将follower的下一个log entry发送。AppendEntries请求总会包含当前log上一个logtermindex,这样的作用是follower会检查上一个termindex处是否有log entry,若没有follower认为当前不应该处理此次AppenEntries请求。在这种情况下leader会将该followernext commit index回退,直到某次请求成功,然后可以安全的将后面的log entry复制过去。这个机制保证了在leader crash的情况下数据一致性。这个leader保证一致性的机制可以做些改进以减少follower拒绝AppendEntries的次数。但是论文作者认为可能没有必要,因为在实践中失败的情况很少。

安全性保证

Raft限制一个candidate成为leader除非它的log包含了所有已经committed log entryCandidate会向所有的节点请求投票(RequestVote,这就意味着,每个committed entry必须在至少其中一个节点上committed。如果candidatelog至少比大多数的节点更新或者一样,说明candidate拥有了所有committed entries。请求投票请求(RequestVote)包含了candidate的最后一个log entryindexterm。节点首先比较term,如果请求的term一致再比较index

Followercandidate失败的情形

Followercandidate失败的情况比较简单,之后的所有请求都会失败,但是leader会持续发送相同的请求直到成功,Raft请求具有幂等性,因此多次请求没有任何影响。

时间和可用性

Raft的一个要求是安全性不依赖于时间。Leader选举是raft协议中时间影响较大的地方。可以认为满足一下不等式的系统,使用raft可以选出并维持一个稳定的leader

broadcastTime << electionTimeout << MTBF

这个不等式中,broadcastTime是一个节点并行发送RPC到每一个节点并收到响应的时间。electionTimeout是前文提到的随机时间值。MTBF是一个节点两失败之间的平均时间。

BroadcastTime需要比electionTimeout小一个数量级,这样leader可以可靠的通过心跳防止follower发起elect过程。ElectionTimeout应该是MTBF小几个数量级。

broadcastTimeMTBF依赖于底层系统,electionTimeout我们可以选择。由于Raft请求会要求持久化,因此根据存储系统的不同broadcastTime可能范围大概是0.5ms-20ms。因此electionTimeout时间值可能为10ms-500ms

集群节点变更

集群的配置更新过程Raft使用了两阶段提交法,raft称之为 joint consensus

1, 所有的log被复制到所有的节点上(新旧配置,这里是集群配置作为一个特殊的log entry

2,任一节点可以被选为leader

3,选出leadercommit的限制:必须是新的大多数和旧的大多数节点

配置变更过程

Leader收到配置变更从ColdCnewleader将这些配置保存在一个log entry中, 使用前述方式复制到所有节点。每个节点收到配置变更的log,会更新自己的配置及时当前log没有commit,每个节点都按照最新的配置运行。这样可以让旧节点知道新节点的存在。同时意味着新节点跟旧节点开始关联,双方不能单方面做出决定。然后leader可以安全的创建一个描述Cnewlog entry并复制到集群,同样的该log也会立即生效即使没有commit。第二个log entry才是“commit”了集群配置的变更,第一个log entry只是知会了Cnew的存在。

这其中有三个问题:

1:新加入一个节点,没有任何log。解决方法是先同步数据再修改配置

2leader不再新的配置中,在Cnew被提交后,leader会立即转换为follower状态,在此前作为leader时,正常处理client请求,但是在计算majorities时不算自己。

3:被摘掉的节点由于收不到心跳,他们会超时发起election过程。解决方法是集群中的节点在小于election Timeout最小间隔时间内不会响应投票请求。


PS:文章是阅读Raft论文根据理解写的,文中配图来源为Raft论文。点击阅读原文打开Raft论文连接。


以上是关于Raft协议的主要内容,如果未能解决你的问题,请参考以下文章

raft 和 zab协议

聊聊分布式一致性协议---Raft协议

Raft协议简析

Raft协议处理各种failover情况

raft协议

Raft 协议学习笔记