Files
MIT6.824/lecture-07-raft2/7.2-xuan-ju-yue-shu-election-restriction.md
2022-01-25 02:41:31 +00:00

6.4 KiB
Raw Permalink Blame History

7.2 选举约束Election Restriction

在前面的例子中我们选择S3作为Leader。现在有个问题是哪些节点允许成为Leader

如果你读了Raft论文那么你就知道答案为了保证系统的正确性并非任意节点都可以成为Leader。不是说第一个选举定时器超时了并触发选举的节点就一定是Leader。Raft对于谁可以成为Leader谁不能成为Leader是有一些限制的。

为了证明并非任意节点都可以成为Leader我们这里提出一个例子来证伪。在这个反例中Raft会选择拥有最长Log记录的节点作为Leader这个规则或许适用于其他系统实际上在一些其他设计的系统中的确使用了这样的规则但是在Raft中这条规则不适用。所以我们这里需要研究的问题是为什么不选择拥有最长Log记录的节点作为Leader如果我们这么做了的话我们需要更改Raft中的投票规则让选民只投票给拥有更长Log记录的节点。

很容易可以展示为什么这是一个错误的观点。我们还是假设我们有3个服务器现在服务器1S1有任期567的Log服务器2和服务器3S2和S3有任期58的Log。

为了避免我们在不可能出现的问题上浪费时间这里的第一个问题是这个场景可能出现吗让我们回退一些时间在这个时间点S1赢得了选举现在它的任期号是6。它收到了一个客户端请求在发出AppendEntries之前它先将请求存放在自己的Log中然后它就故障了所以它没能发出任何AppendEntries消息。

之后它很快就故障重启了因为它是之前的Leader所以会有一场新的选举。这次它又被选为Leader。然后它收到了一个任期7的客户端请求将这个请求加在本地Log之后它又故障了。

S1故障之后我们又有了一次新的选举这时S1已经关机了不能再参加选举这次S2被选为Leader。如果S2当选而S1还在关机状态S2会使用什么任期号呢

明显我们的答案是8因为之前画出来了但是为什么任期号是8而不是6呢尽管没有写在黑板上但是S1在任期67能当选它必然拥有了过半节点的投票过半服务器至少包含了S2S3中的一个节点。如果你去看处理RequestVote的代码和Raft论文的图2当某个节点为候选人投票时节点应该将候选人的任期号记录在持久化存储中。所里在这里S2或者S3或者它们两者都知道任期6和任期7的存在。因此当S1故障了它们中至少一个知道当前的任期是8。这里只有知道了任期8的节点才有可能当选如果只有一个节点知道那么这个节点会赢得选举因为它拥有更高的任期号。如果S2和S3都知道当前任期是8那么它们两者中的一个会赢得选举。所以下一个任期必然为8这个事实依赖于不同任期的过半服务器之间必然有重合这个特点。同时也依赖任期号会通过RequestVote RPC更新给其他节点并持久化存储这样出现故障才不会丢失数据。所以下一个任期号将会是8S2或者S3会赢得选举。不管是哪一个新的Leader会继续将客户端请求转换成AppendEntries发给其他节点。所以我们现在有了这么一个场景。

现在我们回到对于这个场景的最初的问题假设S1重新上线了并且我们又有了一次新的选举这时候可以选择S1作为Leader吗或者说可以选择拥有最长Log记录的节点作为Leader可以吗明显答案是不可以的。

如果S1是Leader它会通过AppendEntries机制将自己的Log强加给2个Followers这个我们刚刚上一节说过了。如果我们让S1作为Leader它会发出AppendEntries消息来覆盖S2和S3在任期8的Log并在S2和S3中写入S1中的任期6和任期7的Log这样所有的节点的Log才能与S1保持一致。为什么我们不能认可这样的结果呢

是的因为S2和S3可以组成过半服务器所以任期8的Log已经被commit了对应的请求很可能已经执行了应用层也很可能发送一个回复给客户端了。所以我们不能删除任期8的Log。因此S1也就不能成为Leader并将自己的Log强制写入S2和S3。大家都明白了为什么这对于Raft来说是个坏的结果吗正因为这个原因我们不能在选举的时候直接选择拥有最长Log记录的节点。当然最短Log记录的节点也不行。

在Raft论文的5.4.1Raft有一个稍微复杂的选举限制Election Restriction。这个限制要求在处理别节点发来的RequestVote RPC时需要做一些检查才能投出赞成票。这里的限制是节点只能向满足下面条件之一的候选人投出赞成票

  1. 候选人最后一条Log条目的任期号大于本地最后一条Log条目的任期号
  2. 或者候选人最后一条Log条目的任期号等于本地最后一条Log条目的任期号且候选人的Log记录长度大于等于本地Log记录的长度

回到我们的场景如果S2收到了S1的RequestVote RPC因为S1的最后一条Log条目的任期号是7而S2的最后一条Log条目的任期号是8两个限制都不满足所以S2和S3都不会给S1投赞成票。即使S1的选举定时器的超时时间更短并且先发出了RequestVote请求除了它自己没人会给它投票所以它只能拿到一个选票不能凑够过半选票。如果S2或者S3成为了候选人它们中的另一个都会投出赞成票因为它们最后的任期号一样并且它们的Log长度大于等于彼此满足限制2。所以S2或者S3中的任意一个都会为另一个投票。S1会为它们投票吗会的因为S2或者S3最后一个Log条目对应的任期号更大满足限制1

所以在这里Raft更喜欢拥有更高任期号记录的候选人或者说更喜欢拥有任期号更高的旧Leader记录的候选人。限制2说明如果候选人都拥有任期号最高的旧Leader记录那么Raft更喜欢拥有更多记录的候选人。