setse 2019-06-28
一个 Raft 集群包含若干个服务器节点;通常是 5 个,这允许整个系统容忍 2 个节点的失效,每个节点处于以下三种状态之一:
follower(跟随者)
:所有结点都以 follower
的状态开始。如果没收到 leader
消息则会变成 candidate
状态。candidate(候选人)
:会向其他结点“拉选票”,如果得到大部分的票则成为leader
。这个过程就叫做Leader选举(Leader Election)。leader(领导者)
:所有对系统的修改都会先经过leader
。Raft通过选出一个leader来简化日志副本的管理,例如,日志项(log entry)只允许从leader流向follower。
基于leader的方法,Raft算法可以分解成三个子问题:
Leader election
(领导选举):原来的leader挂掉后,必须选出一个新的leader
Log replication
(日志复制):leader从客户端接收日志,并复制到整个集群中
Safety
(安全性):如果有任意的server将日志项回放到状态机中了,那么其他的server只会回放相同的日志项
Raft 使用一种心跳机制来触发领导人选举。当服务器程序启动时,他们都是 follower
(跟随者) 身份。如果一个跟随者在一段时间里没有接收到任何消息,也就是选举超时,然后他就会认为系统中没有可用的领导者然后开始进行选举以选出新的领导者。要开始一次选举过程,follower
会给当前term加1并且转换成candidate
状态。
然后他会并行的向集群中的其他服务器节点发送请求投票的 RPCs 来给自己投票。候选人的状态维持直到发生以下任何一个条件发生的时候,
他自己赢得了这次的选举
其他的服务器成为领导者
如果在等待选举期间,candidate接收到其他server要成为leader的RPC,分两种情况处理:
candidate
会转成follower
状态leader
,并继续保持candidate
状态一段时间之后没有任何一个获胜的人
当选出 leader
后,它会开始接受客户端请求,每个请求会带有一个指令,可以被回放到状态机中。leader
把指令追加成一个log entry
,然后通过AppendEntries RPC并行的发送给其他的server,当改entry被多数派server复制后,leader
会把该entry回放到状态机中,然后把结果返回给客户端。
当 follower
宕机或者运行较慢时,leader
会无限地重发AppendEntries给这些follower,直到所有的follower都复制了该log entry。
raft的log replication保证以下性质(Log Matching Property):
其中特性一通过以下保证:
特性二通过以下保证:
如果follower没有发现与它一样的log entry,那么它会拒绝接受新的log entry 这样就能保证特性二得以满足。
在一些一致性算法中,即使一台server没有包含所有之前已提交的log entry,也能被选为主,这些算法需要把leader上缺失的日志从其他的server拷贝到leader上,这种方法会导致额外的复杂度。相对而言,raft使用一种更简单的方法,即它保证所有已提交的log entry都会在当前选举的leader上,因此,在raft算法中,日志只会从leader流向follower。
为了实现上述目标,raft在选举中会保证,一个candidate只有得到大多数的server的选票之后,才能被选为主。得到大多数的选票表明,选举它的server中至少有一个server是拥有所有已经提交的log entry的,而leader的日志至少和follower的一样新,这样就保证了leader肯定有所有已提交的log entry。
领导人知道一条当前任期内的日志记录是可以被提交的,只要它被存储到了大多数的服务器上。如果一个领导人在提交日志条目之前崩溃了,未来后续的领导人会继续尝试复制这条日志记录。然而,一个领导人不能断定一个之前任期里的日志条目被保存到大多数服务器上的时候就一定已经提交了。下图展示了一种情况,一条已经被存储到大多数节点上的老日志条目,也依然有可能会被未来的领导人覆盖掉。
如上图的例子,图(c)就发生了一个log entry虽然已经复制到大多数的服务器,但是仍然有可能被覆盖掉的可能,如图(d),整个发生的时序如下:
为了上图描述的情况,Raft 永远不会通过计算副本数目的方式去提交一个之前任期内的日志条目。只有领导人当前任期里的日志条目通过计算副本数目可以被提交;一旦当前任期的日志条目以这种方式被提交,那么由于日志匹配特性,之前的日志条目也都会被间接的提交。例如,图e中,如果S1在挂掉前把log entry(4)复制到了大多数的server后,就能保证之前的log entry(2)被提交了,之后S5也就不可能被选为领导者了。
以反证法来证明,假设任期 T 的领导人(领导人 T)在任期内提交了一条日志条目,但是这条日志条目没有被存储到未来某个任期的领导人的日志中。设大于 T 的最小任期 U 的领导人 U 没有这条日志条目。
如果 S1 (任期 T 的领导者)提交了一条新的日志在它的任期里,然后 S5 在之后的任期 U 里被选举为领导人,然后至少会有一个机器,如 S3,既拥有来自 S1 的日志,也给 S5 投票了。
投票者把自己选票投给领导人 U 时,领导人 U 的日志必须和投票者自己一样新。这就导致了两者矛盾之一。
跟随者或者候选人崩溃,会按如下处理:
领导人选举是 Raft 中对时间要求最为关键的方面。Raft 可以选举并维持一个稳定的领导人,只要系统满足下面的时间要求:
广播时间(broadcastTime) << 选举超时时间(electionTimeout) << 平均故障间隔时间(MTBF)
选举超时时间要大于广播时间的原因是,防止跟随者因为还没收到领导者的心跳,而重新选主。
选举超时时间要小于MTBF的原因是,防止选举时,能正常工作的server没有达到大多数。
对于广播时间,一般在[0.5ms,20ms]之间,而平均故障间隔时间一般非常大,至少是按照月为单位。因此,一般选举超时时间一般选择范围为[10ms,500ms]。因此,当领导者挂掉后,能在较短时间内重新选主。