客户端如何知道新的 leader 是哪个节点?
客户端向老 leader 发送请求:
- 正好是新 leader
- 变成 candidate,提供新 leader 信息
- 宕机了,向其他节点再发送请求
日志格式
一条日志中需要有三个信息:
状态指令、leader 的任期号、日志号
只有日志号和任期号才能确定唯一的一个日志(例如 leader 宕机,这个时候日志号相同,但是日志内容可能不同)
leader 并行发送 AppendEntries RPC 给 follower,当超过半数 follower 复制后,leader 就可以在本地执行该指令并把结果返回给客户端
把本地执行指令这一步称作提交

图中可以提交的位置为 log index 为 7 的日志
如何让 follower 追上 leader?
- follower 缓慢:leader 不断重发追加条目请求,哪怕 leader 已经回复了客户端
- follower 宕机:Raft 追加条目的一致性检查生效,保证 follower 能够按照顺序恢复崩溃后的确实的日志
- leader 在每一个发往 follower 的追加条目 RPC 中,会放入前一个日志的索引和任期号,follower 找不到则拒绝,leader 会发送更前面的一个日志,直至找到没有冲突的日志
- 上面描述的过程可以优化,比如 follower 在拒绝的时候可以直接发送自己该任期内的最后一个日志,或者是使用二分查找,但是作者确认为这是没有必要的,会让设计变得更复杂,失败不经常发生,并且也不可能有很多不一致的日志条目
- leader 宕机:崩溃的 leader 可能存在一些日志已经复制到了部分 follower 但是新的 leader 可能又不具备这些日志
- 对外,客户端会认为未提交的日志直接是失败的,不会影响对外一致性
- 但是这台 leader 宕机恢复后就会出现问题了,他会变成 follower,并且收到新 leader 的 RPC,发现自己最后几个日志和新 leader 的日志出现了不同,这个时候 follower 中的跟 leader 冲突的日志条目会被新的 leader 的日志条目覆盖(因为没有提交,所以不违背外部一致性)
总结
- leader 在当权后不需要任何的操作来使日志恢复到一致状态
- leader 只需要进行正常的操作,然后日志就能在恢复 Append Entries 一致性检查失败的时候自动趋于一致