任期 Term
Raft把时间分割成任意长度的任期,任期用连续的整数标记。每一段任期从一次选举开始。
term是一个逻辑时钟,因此,当一台机器在与其他机器通信时发现自己的term比较小,应该推进本地的term。如果一台机器发现请求方的term比较小,则要拒绝请求。如果一个candidate发现自己的term落后了,就要退回到follower。
Raft协议的每个副本都会处于三种状态之一:
Leader:处理所有的client请求,本地处理后同步至其他副本
Follower:被动的更新者
Candidate:Follower副本在一段时间内没有收到leader副本的心跳,则判断leader可能已经故障,此时启动选主过程,follower变为candidate状态。
选举过程
参与选举
每个term一开始就进行选主:
Follower将自己的current_term_id + 1(需要持久化),并转换自己称为Candidate
发送RequestVoteRPC给其他所有的server。
Candidate状态持续到以下三种情况发生
a) 该candidate赢得了选主
b) 其他机器成为了leader
c) 超时间内未能选主成功
一个candidate赢得选主的判定:在相同的term内,收到了多数派的投票。
选主成功之后,新主向其他主机发送心跳AppendEntries RPC,宣告自己当选了。
在选主时间内, candidate如果收到了其他主机宣告当选的心跳AppendEntries RPC且RPC中携带的term比本机维护的term更大或相等,本机就自动退为follower。
若在一个term内选主失败时,所有candidate递增term开始下一轮。为了减少选票分裂出现的概率,选举超时时间使用随机化的方法避开多个candidate同时拉票。
投票机制
raft确保leader是当前多数派中拥有最新日志的节点, 以此来确保日志流只从leader流向follower而无需从
不落后的follower拉去日志。
首先,在给定的term内,每台机器都只能按照先来先服务的规则投一个candidate(要持久化)。
其次,保证包含所有commit日志的candidate才能有机会被选为leader。因为一条日志commit,必然在任意一个多数派中,至少有一台主机包含了这条日志。选举时,candidate要和至少多数派的主机通信,通信时带上自己本地的日志信息(本地最后一条的term和log id),接收消息的主机发现发送消息的candidate的日志并不比我本地更新,就拒绝投票。也就是说,candidate至少是某个多数派中拥有最新日志的主机,才能被选为leader。