那么假设raft算法中3台服务器的日志配置如下:
S1 -> 3
S2 -> 3 3 4
S3 -> 3 3 5
如果假设 S3 是第 3 项中的领导者,则条目已提交给每个副本,然后在具有相同领导者 S3 的另一个客户端操作中,它只能复制 S2 中的条目及其自身,然后崩溃。之后S2凭借自身和S1的选票赢得选举。它获取一个条目并将其输入到日志中,然后崩溃。 S3 再次回来,然后获得 S1 和自身的投票,成为领导者,在第 5 项中进入另一个日志,然后崩溃。
现在我们遇到的情况是第 4 项和第 5 项中的条目肯定不会提交。假设 S2 再次成为领导者(从自己和 S1 获得投票),它将尝试纠正追随者中的日志,最终会覆盖并附加到两个追随者以获得:
S1 -> 3 3 4
S2 -> 3 3 4
S3 -> 3 3 4
在我看来,删除第 5 项中的日志是公平的,因为领导者可能不会向客户端回复完成消息,因为第 5 项中的条目复制在大多数服务器上都没有完成。但是,相同的论点对于第 4 项的条目是否有效,如果是的话,为什么它会在各处复制。客户端也不会获得第 4 项中条目的完成响应,因此客户端会认为状态机不会运行此操作,但通过上述逻辑它会运行。
有人愿意解释一下吗?
“之后,S2 凭借自身和 S1 的投票赢得了选举。它获得一个条目并将其输入到日志中”
当节点成为领导者时,保证其拥有最新的日志;并且日志包含提议的条目和提交的条目。 在新的领导者处理请求之前,它会向每个追随者发送一条空消息;该消息携带日志信息,如果某些追随者落后,领导者可能会得出结论。对于落后的人,领队将运送所有缺失的参赛作品。
此时领导者和多数人具有相同的日志,领导者可以继续提交未提交的条目;然后接受新的请求。
查看原始论文:https://raft.github.io/raft.pdf第4页 - AppendEntries RPC:接收器实现。
步骤#1。初始状态,S3领导者一切正常,索引10已提交
10 11 12
S1 -> 3
S2 -> 3
S3 -> 3
步骤#2。然后在具有相同领导者 S3 的另一个客户端操作中,它只能复制 S2 中的条目及其自身,然后崩溃。
10 11 12
S1 -> 3 // S1 crashed
S2 -> 3 3
S3 -> 3 3
步骤#3。之后S2凭借自身和S1的选票赢得选举。它获取一个条目并将其输入到日志中,然后崩溃。
10 11 12
S1 -> 3 // S1 came back up, now at term 4
S2 -> 3 3 4 // S2 is new leader (term 4), got entry at Index 12,crashed
S3 -> 3 3 // S3 (old leader) crashed, is down and election started
步骤#4。 S3 再次回来,然后获得 S1 和自身的投票,成为领导者,在第 5 项中进入另一个日志,然后崩溃。
10 11 12
S1 -> 3 // S1 is up at term 5
S2 -> 3 3 4 // S2 is down
S3 -> 3 3 5 // new election term 5, becomes leader, gets entry at 12
但真正的问题是在步骤 #4 中,为什么选择 S3 作为领导者?它的最后一个已知术语只有 3,因为当术语变为 4 时,S3 已关闭。