Raft 如何处理长时间的网络分区?

How does Raft handle a prolonged network partition?

考虑我们在 3 台机器上 运行ning Raft:A、B、C,让 A 成为领导者。有一个网络分区将 C、A、B 分开。将当前项称为 t。 A 和 B 保持在第 2 期,除了定期心跳之外没有其他消息。此时C进入candidate状态,term加3,投给自己,超时,重复。比如说 10 个周期之后,网络分区就解决了。现在状态是A[2], B[2], C[12]; C 将拒绝来自 A 的 AppendEntries RPC,因为任期 2 小于其当前任期 10; C 不能 assemble 法定人数,将继续 运行 作为候选人的领导者选举协议,并且与 A 和 B 的当前任期值越来越不同。

那么问题来了,Raft(或者Raft派生的实现)是如何处理这个问题的?我包括的一些想法:

  1. 这种情况是可用性问题,而不是安全违规。通过杀死或重置 C
  2. 忽略并让人工操作员处理
  3. 指数退避以减少每次选举 C 的分歧
  4. 让 C 使用 lastApplied 而不是 currentTerm 作为拒绝或接受 AppendEntries RPC 的基础。也就是说,我们相信日志是术语的真实来源,而不是 currentTerm 值。这已经用于确保 C 不会根据选举限制获胜,但是该文件似乎表明此“最新”属性 是不投票给 C 的理由,但不是理由为C默许并重置为follower。

注意:术语根据 In Search of an Understandable Consensus Algorithm (Extended Version)

当 C 拒绝领导者 A 的 AppendEntries RPC 时,它将 return 现在是 > 2 任期。 Raft 副本总是 识别更大的条款,因此反过来将导致领导者下台并开始新的选举。最终,集群将收敛于一个新的术语 > 2,也就是 >= C 的术语。

这是一个经常讨论的(在 Raft 开发社区中)有点不方便的场景,它可能会导致 Raft 集群中不必要的变动。为了防止它,Raft 论文——以及大多数现实世界的实现——引入并使用了所谓的“预投票协议”。 The pre-vote protocol essentially dictates that before becoming a candidate, a follower must first determine whether it can win an election by asking its peers.在您上面描述的场景中,C 会要求 A 和 B 进行预投票,并且由于网络分区,它不会收到任何投票。因此,C 永远不会过渡到候选角色,永远不会增加任期,因此在分区修复后永远不会出现任期 > 2。因此,您已经消除了流失。

您可以在 Diego 的论文中阅读有关投票前协议的更多信息。