1

在实现 Raft 算法时,我发现有一种情况我认为可能对集群造成伤害,也可能不会。

假设一些来自 Leader 的 AppendEntriesRPC 被重新排序(网络延迟或其他原因)是合理的。考虑领导者向对等点 A 发送心跳 AppendEntriesRPC,使用prev_log_index = 1,然后发送另一个带有条目 2 的 AppendEntriesRPC,然后它崩溃(我确保通过我的测试中的回调立即发生这种情况)。如果两个 RPC 按发送顺序处理,则条目 2 将成功插入。但是,如果心跳 RPC 延迟,那么 peer A 会首先插入 entry 1 并响应 Leader。然后是延迟的心跳,peer A 将删除条目 2,因为该条目与 Le​​ader 的 冲突prev_log_index = 1。所以对等体 A 错误地删除了一个日志条目。

再深入一点,如果Leader不立即崩溃,它会解决这个问题吗?我认为如果 peer A 正确响应延迟的心跳,Leader 会在以后的一些 RPC 中发现并修复它。

但是,如果对等体 A 对条目 2 的响应导致commit_index前进怎么办?在这种情况下,节点 A 投票支持前进commit_index到 2,即使它实际上没有条目 2。因此可能没有足够的票数来支持前进。现在当Leader崩溃时,日志较少的节点将被选为Leader。我在测试过程中确实遇到过这种情况。

我的问题是:

  1. 我的推理正确吗?
  2. 如果重新排序 RPC 是一个真正的问题,我应该如何解决?对所有 RPC 进行索引和缓存,并强制它们一一处理是一个好的解决方案吗?我发现在 gRPC 中很难实现。
4

1 回答 1

0

Raft 假设一个有序的流协议,例如 TCP。也就是说,如果一条消息无序到达,那么它会被缓冲,直到它的前任到达。(这种行为就是 TCP 存在的原因:因为每个单独的数据包都可以通过服务器之间的单独路由,并且很有可能出现乱序消息,并且大多数应用程序更喜欢易于使用的严格排序。)

其他协议,例如普通的旧 Paxos,可以处理乱序消息,但通常比 Raft 慢得多。

于 2019-01-23T05:54:40.640 回答