Raft 如何处理 AppendEntries RPC 中的延迟回复?

How does Raft deals with delayed replies in AppendEntries RPC?

我在阅读 Raft paper 时提出了一个问题。场景如下。有3个新启动的Raft实例,R1,R2,R3。 R1被选为leader,nextIndex为{1, 1, 1},matchIndex为{0, 0, 0},任期为1。现在它收到来自客户端的命令1,实例的日志如下:

R1: [index 0, command 0], [index 1, command 1]
R2: [index 0, command 0]
R3: [index 0, command 0]

如果网络不可靠怎么办?如果 R1 正在向 R2 发送此日志,但 AppendEntries RPC 超时,领导者 R1 必须再次重新发送 [index 1, command 1]。那么它可能会收到两次回复{term: 1, success: true}。

论文说:

If last log index ≥ nextIndex for a follower: send AppendEntries RPC with log entries starting at nextIndex
• If successful: update nextIndex and matchIndex for follower (§5.3)
• If AppendEntries fails because of log inconsistency: decrement nextIndex and retry (§5.3)

所以leader R1会增加nextIndex和matchIndex两次:nextIndex {1, 3, 1}, matchIndex {0, 2, 0},这是不正确的。当领导者发送下一个 AppendEntries RPC,即心跳或日志复制时,它可以修复 nextIndex,但 matchIndex 永远没有机会被修复。

我的解决方案是为每个 RPC 调用的 AppendEntries 参数和结果添加一个序列号。不过我想知道有没有办法只用论文给的参数,也就是不用序号就可以解决这个问题。

如有任何建议,我们将不胜感激,并提前致谢。

该协议假定存在关于 跟随者正在响应的 AppendEntries RPC 的一些上下文。因此,在某种程度上确实需要一个序列号(或更准确地说是一个相关 ID),无论是在协议层、消息传递层还是在应用程序本身。领导者必须有某种方法将请求与响应关联起来,以确定 跟随者正在确认哪个 索引。

但实际上还有一个不常被讨论的替代方案。 Raft 协议的一些修改让追随者在响应中发送他们最后的日志索引。您还可以使用最后一个日志索引来确定哪些索引已保存在关注者上。