一个 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从客户端接收日志,并复制到整个集群中spa
Safety
(安全性):若是有任意的server将日志项回放到状态机中了,那么其余的server只会回放相同的日志项日志
Raft 使用一种心跳机制来触发领导人选举。当服务器程序启动时,他们都是 follower
(跟随者) 身份。若是一个跟随者在一段时间里没有接收到任何消息,也就是选举超时,而后他就会认为系统中没有可用的领导者而后开始进行选举以选出新的领导者。要开始一次选举过程,follower
会给当前term加1而且转换成candidate
状态。code
而后他会并行的向集群中的其余服务器节点发送请求投票的 RPCs 来给本身投票。候选人的状态维持直到发生如下任何一个条件发生的时候,server
他本身赢得了此次的选举rem
其余的服务器成为领导者get
若是在等待选举期间,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]。所以,当领导者挂掉后,能在较短期内从新选主。