5.4.3 安全性论证
给出完整的Raft算法,现在我们能够更精确地论证Leader
完备性原则(这个论证基于安全性证明;详见9.2节
)。我们假定Leader
完备性原则是不成立的,然后推导出矛盾。假定Leader
在任期T(leaderT)提交了一个日志条目,但是这个日志条目并没有存储在下一个任期中的Leader
上。假设最小的任期U>T
,Leader
(leaderU)没有存储这个日志条目。
图-9:如果 S1(任期T的Leader)在它的任期提交了一个日志条目,并且 S5 在之后的任期 U 成为 Leader,那么最少会有一个 Server(S3)接收了这个日志条目,并且会投票给 S5。
- 在leaderU选举时,一定没有那个被提交的日志条目(
Leader
从来不会删除或者覆盖日志条目)。 - leaderT在集群的大多数
Server
上复制了这个条目。因此,至少有一个Server
(投票者)既接收了来自leaderT的日志条目,又投票给leaderU,如图-9
所示。这个投票者是产生矛盾的关键。 - 投票者必须在给 leaderU投票之前接收来自leaderT的已提交日志条目;否则它会拒绝来自leaderT的
AppendEntries
请求(它的当前任期会比T要大)。 - 投票者会在它给leaderU投票时存储那个条目,因为任何中间的
Leader
都保有该条目(基于假设),Leader
从来不会移除这个条目,并且Follower
也只会在和Leader
冲突时才会移除日志条目。 - 投票者给leaderU投票了,所以leaderU的日志必须和投票者的一样新。这就导致了一个矛盾。
- 首先,如果投票者和leaderU最后一条日志条目的任期编号相同,那么leaderU的日志一定和投票者的一样长,因此它的日志包含全部投票者的日志条目。这是矛盾的,因为在假设中投票者和leaderU包含的已提交条目是不同的。
- 除此之外,leaderU的最后一条日志的任期编号一定比投票者的大。另外,它也比T要大,因为投票者的最后一条日志条目的任期编号最小也要是T(它包含了所有任期T提交的日志条目)。创建leaderU最后一条日志条目的上一任
Leader
必须包含已经提交的日志条目(基于假设)。那么,根据日志匹配原则(Log Matching),leaderU也一定包含那条提交的日志条目,这也是矛盾的。 - 这时就完成了矛盾推导。因此,所有比任期T大的
Leader
一定包含所有在任期T提交的日志条目。 - 日志匹配原则(Log Matching)保证了未来的
Leader
也会包含被间接提交的日志条目,就像图-8
中(d)时刻索引为2的条目。
通过给出了Leader
完备性原则(Leader Completeness),我们能够证明表-3
中的状态机安全原则(State Machine Safety)。状态机安全原则(State Machine Safety)讲的是,如果一个Server
将给定索引上的日志条目应用到了它自己的状态机上,其它Server
的同一索引位置不可能应用的是其它条目。在一个Server
应用一条日志条目到它自己的状态机中时,它的日志必须和Leader
的日志在该条目和之前的条目上相同,并且已经被提交。现在我们来考虑在任何一个Server
应用一个指定索引位置的日志的最小任期;日志完整性特性(Log Completeness Property)保证拥有更高任期编号的Leader
会存储相同的日志条目,所以之后的任期里应用某个索引位置的日志条目也会是相同的值。因此,状态机安全特性是成立的。
最后,Raft
算法需要Server
按照日志中索引位置顺序应用日志条目。和状态机安全特性结合起来看,这就意味着所有的Server
会应用相同的日志序列集到自己的状态机中,并且是按照相同的顺序。