raft主要分成三个部分:
在系统初始化时,所有的节点都会被初始化为follower,leader会被选举出来。follower会周期性的接收到来自leader的心跳rpc,以维持follower的状态。若在选举超时时间内没有收到rpc,follower就会选举超时,该超时时间在一个范围内随机(如150-300ms)。超时后,follower就自增自己的currentTerm,成为candidate,并给自己投票,然后向其他服务器发送投票请求rpc,follower处理投票请求rpc时遵循先到先得的与原则。candidate会一直处于这个状态直到下列某一情况发生:
以一个请求来说明日志的复制流程: leader
leader需要根据集群节点对AppendEntires的响应来判断一条日志是否被复制到半数以上节点。当leader收到半数以上的响应,就认为该日志已经复制成功。此时leader宕机时,后续新当选的领导人肯定是在已成功接收最新日志的节点中产生,还是能保证该日志被提交。
日志数据不一致问题: Raft通过将将leader日志复制到follower节点,并覆盖follower节点中与leader不一致的日志。leader节点为每个节点存储了两个记录:
AppendEntries RPC 中包括:
状态的持久化存储和server的重启:
领导权转移: Raft允许server将自己的领导权转移其他的server,有两种场景:
为了选举能够成功,当前leader需要将自己的log entries发送给目标Server,保证目标server上持有所有提交的log entries,但后发起leader竞选,不需要等待选举超时。
当目标server失败时,当前leader就会中断领导权转移过程,恢复客户端请求处理。
现在还有两个问题:
为了解决新成员加入时,成员需要追赶leader日志的问题,raft 引入了 non-voting server,等到日志同步完成时再开始加入集群。首先会引入round的概念,每个round开始时,leader将non-voting server少于leader的日志同步到non-voting server,round中新接收的日志会在下一个round同步。 若没有新日志发送到leader时,一个round开始会马上结束,进入下一个round,当进行round的次数超过阈值时,leader就将新的server加入到集群
当前leader的移除 当要下线集群的leader时,首先客户端会发送一条C new的配置请求,C new会以日志的形式复制到集群大多数节点 , 只有当该日志提交之后,leader才可以转变为follower再进一步下线,只有当C new复制到大多数节点,集群才有可能从C new的成员中选举出leader。leader才可以转变为follower,此时C new的成员会选举超时,从而选举产生 leader。旧 leader的不可用到新leader的产生的这段时间系统是处于不可用的状态。 下线成员对系统的扰动 当下线非leader节点时,该节点就收不到新的配置C new,也就不知道自己是否下线,此时leader上新的配置生效之后,就 不再给将要下线的节点发送heartbeat。该节点就会超时并发起选举,选举会扰乱当前系统leader的工作,由于周期高于当前leader,leader就会转变为follower, 发起选举的节点不在系统内不会当前选,系统内会重新选举出一个leader。所以 raft提出了一个已解决方案: 为leader竞选阶段引入一个新的阶段,pre-vote,candidate发起投票之前会询问其他节点自己的日志是否足够新的来竞选leader。但pre-vote的引入并不能解决上述问题。
前面描述的选举和日志复制机制还不能完全保证每个状态机都能根据相同的日志按照相同的顺序执行命令。例如一个follower因为网络问题错过了多次的日志复制,然后网络恢复,集群leader宕机,follower当选为leader,该follower缺少上一个leader 提交的日志,就会导致这些日志被新的leader覆盖。
随着raft处理客户端请求的增长,日志记录也会越来越长,占用的存储空间也会越来越多,也会花费越来越多的时间进行日志重放。但在一个实际的系统当中,存储空间不可能没有限制,因此采取一种机制来丢弃部分日志记录势在必行。 快照是最简单的进行日志压缩的方式。 每个节点独立的生成快照 ,通过将整个状态机的状态都写入快照然后存储到稳定的存储介质上方式,可以允许快照点之前的所有日志可以被删除。Raft还会在快照中保存一部分元数据,也就是快照可以替换的所有日志记录的最一条(最后一条状态机执行的日志记录),这条日志是用来做AppendEntries时的日志一致性检查的。同时为了保证集群成员变化,快照中还会保存应用最后一条日志时的配置文件。