maemual/raft-zh_cn

5.4.3 安全性论证中反证法第5、6点结论有些困惑

guhanjie opened this issue · 1 comments

image
反证过程中第5、6点结论如下:

  1. 投票者把自己选票投给领导人 U 时,领导人 U 的日志必须和投票者自己一样新。这就导致了两者矛盾之一。
  2. 首先,如果投票者和领导人 U 的最后一条日志的任期号相同,那么领导人 U 的日志至少和投票者一样长,所以领导人 U 的日志一定包含所有投票者的日志。这是另一处矛盾,因为投票者包含了那条已经被提交的日志条目,但是在上述的假设里,领导人 U 是不包含的。

但是会否存在这样的情况:

index 1 2 3 4 5 6
投票者 1 1 2 2 2 3
U 1 1 2 2 3 3

这种情况下,投票者和领导人 U 的最后一条日志的任期号相同,日志长度也相同,但是领导人U并不包含那条已经被提交的日志条目(index=5的日志),这便无法构建矛盾

或者这样的情况:

index 1 2 3 4 5 6 7 8
投票者 1 1 2 2 3 3
U 1 1 2 2 2 2 3 3

自问自答
上面提到的第一种情况不存在,这是由日志匹配特性所决定的:

我们设计了 Raft 的日志机制来维护一个不同服务器的日志之间的高层次的一致性。这么做不仅简化了系统的行为也使得更加可预计,同时他也是安全性保证的一个重要组件。Raft 维护着以下的特性,这些同时也组成了图 3 中的日志匹配特性:

  • 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们存储了相同的指令。
  • 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们之前的所有日志条目也全部相同。

第一个特性来自这样的一个事实,领导人最多在一个任期里在指定的一个日志索引位置创建一条日志条目,同时日志条目在日志中的位置也从来不会改变。第二个特性由附加日志 RPC 的一个简单的一致性检查所保证。在发送附加日志 RPC 的时候,领导人会把新的日志条目紧接着之前的条目的索引位置和任期号包含在里面。如果跟随者在它的日志中找不到包含相同索引位置和任期号的条目,那么他就会拒绝接收新的日志条目。一致性检查就像一个归纳步骤:一开始空的日志状态肯定是满足日志匹配特性的,然后一致性检查保护了日志匹配特性当日志扩展的时候。因此,每当附加日志 RPC 返回成功时,领导人就知道跟随者的日志一定是和自己相同的了。


上面提到的第二种情况也不存在,这是由AppendEntries RPC规则所决定的:
image
文中5.3节中提到:

在 Raft 算法中,领导人处理不一致是通过强制跟随者直接复制自己的日志来解决了。这意味着在跟随者中的冲突的日志条目会被领导人的日志覆盖。5.4 节会阐述如何通过增加一些限制来使得这样的操作是安全的。

要使得跟随者的日志进入和自己一致的状态,领导人必须找到最后两者达成一致的地方,然后删除从那个点之后的所有日志条目,发送自己的日志给跟随者。所有的这些操作都在进行附加日志 RPCs 的一致性检查时完成。领导人针对每一个跟随者维护了一个 nextIndex,这表示下一个需要发送给跟随者的日志条目的索引地址。当一个领导人刚获得权力的时候,他初始化所有的 nextIndex 值为自己的最后一条日志的 index 加 1(图 7 中的 11)。如果一个跟随者的日志和领导人不一致,那么在下一次的附加日志 RPC 时的一致性检查就会失败。在被跟随者拒绝之后,领导人就会减小 nextIndex 值并进行重试。最终 nextIndex 会在某个位置使得领导人和跟随者的日志达成一致。当这种情况发生,附加日志 RPC 就会成功,这时就会把跟随者冲突的日志条目全部删除并且加上领导人的日志。一旦附加日志 RPC 成功,那么跟随者的日志就会和领导人保持一致,并且在接下来的任期里一直继续保持。

如上第二种情况,其实在Term=3的任期里,有index=5和index=6的日志条目,根据上面的AppendEntries RPC实现规则所描述,在U的日志中,是不可能存在漏掉这两个日志条目的情况,而可能是会覆盖,然后就转变成第一种情况(存在相同的index和term),然后就可以推出U中包含已提交的日志(index=5)

总结:
以上的质疑,都被本算法的AppendEntries RPC实现规则中的一致性检查所解决。