raft本质理解

本文记录关于raft的关键理解,基础概念就不赘述了。

raft关键在于抽屉理论,二阶段,选举约束,一共3个部分。

抽屉理论基本都懂,5个人中有3个男人,那么任意抽3个人至少有1个男人。

leader处理请求分4步:

  1. 日志复制给半数节点,失败无限重试
  2. 半数复制成功,则本地commit提交(写提交日志,执行业务逻辑),为啥leader此刻义无反顾?继续往后看。
  3. 返回客户端告知成功,leader给用户承诺结果了,这是raft算法要坚决想办法保证的。
  4. leader异步的把commit事件广播给follower们。

上述先复制,再广播提交对于follower们就是2阶段。

这4步依次完成,中间任何一步leader宕机,都需要有恢复机制,但是我需要先说一下选举的约束:

  • 需要半数以上节点给你投票,你才能成为leader
  • 成为leader的节点,其记录的commited日志条数必然是投票者中最多的,否则其他节点不会给你投票
  • 如果多个节点commited日志一样多,那么看谁uncommit日志的term更大,条数更多。

接下来,我们看raft是如何处置异常场景的。

1,leader复制给少数节点,然后宕机。

leader肯定没有机会commit这条日志,其他节点进行选举。

如果复制成功的少数节点在选举行列中,那么因为它们相比其他节点有uncommit日志,所以优先成为leader。(至于uncommit的日志要不要commit,我们后面说)

如果选举之中没有复制成功节点,那么新leader会通知复制成功节点删除自己的uncommit日志。

因为这个场景压根没有给客户端承诺,所以是新Leader重新提交还是丢弃日志,都无所谓。

2,leader复制给多数节点,然后宕机。

其他节点进行选举,根据抽屉理论,至少有1个复制成功的节点在选举之列,必然成为leader。(至于uncommit的日志要不要commit,我们后面说)

这个场景虽然没有给客户端承诺,但是日志并没有丢,所以日志一旦被后续提交,会导致客户端重试请求时发生重复操作。

3,leader复制给多数节点,本地提交成功,返回客户端成功,然后宕机。

leader没来得及广播commit给follower,或者只广播commit了少数节点,然后其他节点进行选举。

如果commit节点在选举行列,那么它比其他节点commit的日志更多,成为leader。

如果commit节点不在选举行列,根据抽屉理论,其他节点中至少有1个节点是复制过日志的,那么复制成功节点成为leader,它的日志序列和commit过的节点一样,无非是日志没有被commit。

这个场景承诺了客户端,无论如何日志是不允许丢的,所以上述2个分支的leader都拥有日志,只是一个commit过了一个没commit过,所以没commit过的一定要想办法commit掉。

4,leader复制给多数节点,本地提交成功,返回客户端成功,广播commit给了多数节点,然后宕机。

其他节点选举,根据抽屉理论,至少有1个commit成功的节点参与选举,成为leader。

给客户端承诺了,新leader也是commit过的,所以没有问题。

最后就是针对场景1与2,新leader是否应该立即commmit日志的问题。

答案是,不应该立即commit前任leader的日志,而是当leader收到新的请求并复制给大多数节点后,把老日志和新日志一起commit提交,并广播给follower。

新Leader不能直接commit前任留下的日志是有原因的,否则会导致raft算法错误。

参考

《1620秒入门raft》

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~