客户端如何知道新的 leader 是哪个节点?

客户端向老 leader 发送请求:

日志格式

一条日志中需要有三个信息:

状态指令、leader 的任期号、日志号

只有日志号和任期号才能确定唯一的一个日志(例如 leader 宕机,这个时候日志号相同,但是日志内容可能不同)

leader 并行发送 AppendEntries RPC 给 follower,当超过半数 follower 复制后,leader 就可以在本地执行该指令并把结果返回给客户端

把本地执行指令这一步称作提交

image.png

图中可以提交的位置为 log index 为 7 的日志

如何让 follower 追上 leader?

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

总结