3

我在阅读Raft 论文时提出了一个问题。剧情如下。有 3 个新启动的 Raft 实例,R1、R2、R3。R1被选举为leader,nextIndex {1, 1, 1},matchIndex {0, 0, 0}和term 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},这是不正确的。当leader发送下一个AppendEntries RPC,即心跳或日志复制时,它可以修复nextIndex,但matchIndex永远没有机会被修复。

我的解决方案是为每个单独的 RPC 调用添加一个序列号到 AppendEntries 参数和结果中。但是,我想知道是否有一种方法可以仅使用论文给出的参数来解决这个问题,即没有序列号。

任何建议将不胜感激,并提前感谢您。

4

1 回答 1

4

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

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

于 2019-06-20T01:10:42.597 回答