Raft中的领导人选举

分布式一致性问题

Posted by bbkgl on October 22, 2019

原来姹紫嫣红开遍

似这般都付与断井颓垣

极简解释

为了能够很容易地浏览整个过程,先从一个最小的Raft民主集群出发,即一开始是3个群众(单数是为了能让某个候选人拿到多数票)。如下图,发起选举时,有可能发生如下三种情况。

H0ba532d8054c4db290b3a53f2ea5e2c5o

可以看出,前两种都能够选出领导人,第三种因为“瓜分”选票的原因,没有候选人拿到多数选票,则本轮选票无效。之后会再次发生超时(Election Timeout),最先发起投票的一方会获得多数选票,成为领导人。简单地说,最先超时并恢复的一方会首先向还在Timeout中的另外两方请求投票(拉票),而因为这两方还在Timeout中,自能将选票投给对方。所以也就体现了论文中的那句话,“Raft uses randomized election timeouts to ensure that split votes are rare and that they are resolved quickly.(Raft 算法使用随机选举超时时间的方法来确保很少会发生选票瓜分的情况,就算发生也能很快的解决)”。

选举过程

两种timeout

  • election timout(选举超时):群众变成候选人需要的时间,随机值,在150-300ms之间;根据论文描述,候选人在开始候选后也会生成一个选举超时,在选举超时后会重置超时;
  • heartbeat timeout(心跳超时):领导人发送心跳包的间隔事件称为心跳超时。

选举超时是对群众和候选人而言的,心跳超时是对领导人而言的,理解这点很重要。

重置选举超时的情况

  • 群众接受候选人的请求投票,这时候会重置自己的选举超时,并增加任期
  • 群众接收到了领导人的心跳包或者是增加日志条目的消息
  • 如果候选人在选举超时内没有成为领导人,也没有其他的节点成为领导人,则会重置超时

候选人等待的三种情况

要开始一次选举过程,群众需要变成候选人(经过一次election timout的时间),把自己的选票投给自己,并且增加自己的任期号(term)。然后会并行地向集群中的其他所有节点发送请求投票的RPC(前一篇博文中提到的RequestVote RPC)。随后候选人会等待出现以下三种情况之一的发生:

  1. 自己拿到了多数选票,成为领导人

  2. 其他的候选人率先成为领导人

  3. 没有一个候选人获得多数选票,没有领导人出现

第一种情况发生的话,候选人会赢得本次选举,并立即成为领导人。这里需要说明的是,每个节点只有一张选票,一旦自己成为了候选人,这张选票就投给了自己,每个群众投票遵从先来先服务的原则。领导人确定后,就会发送心跳RPC(前一篇博文中提到的AppendEntries RPC)来建立和维持自己的统治,防止其他群众出现heartbeat timeout(心跳超时)

Hd2561679ac9a48a1a5a7e2134d2cd0c3R

第二种情况,也就是候选人收到了别的领导人发送的心跳RPC,其实就是AppendEntries RPC。如果RPC参数中的任期大于等于候选人当前任期号,则接受对方的领导地位,并成为群众;或者是其他候选人的任期大于自己的任期,也会投出自己的选票;如果不满足任期条件,会拒绝对方的RPC,即返回false,并且继续保持候选人状态,继续等待以上三种情况之一发生。

第三种情况,候选人“瓜分选票”,没有人获得多数选票,然后其他候选人也没有获得多数选票。这种情况下,每个候选人都会发生超时。

Hee1f7c4d9fa945df9daf73b36c987827J

当这种情况发生的时候,每一个候选人都会超时,然后通过增加当前任期号来开始一轮新的选举。然而,没有其他机制的话,选票可能会被无限的重复瓜分。

Raft算法是如何处理这种情况的?使用随机的选举超时和随机的重置选举超时。首先“随机的选举超时”就会使得同时出现多个候选人的情况很少,其次就算出现了多个候选人瓜分选票,那随后候选人恢复后重置的随机选举超时也会很大程度避免第二轮的瓜分选票,也就是越往后,出现瓜分选票的概率越低,这样就极大地降低了第三种情况发生的概率。还有一个关键点是任期,很多值的改变以及决定需要与任期(term)进行匹配。很多细节需要考虑任期,否则会很难理解。

一些问题

在Raft论文中关于以下细节并没有讲,我需要在其他地方进行补充

  1. 候选人候选超时并重置超时后,任期怎么变?

    候选人重置超时后,任期会直接+1,需要注意的是选举超时(election timeout)同时也是候选人每一轮候选的超时时间,是一个随机值!!!!

  2. 群众接受投票后,是否会重置选举超时?任期怎么变?

    群众接受投票后,会重置选举超时,自己的任期取决于候选人发送的RPC参数,如果对方参数中任期大于自己的任期,则修改任期与对方一致,并给出自己的选票。

  3. 候选人候选期间,接受别人的请求投票吗?如果对方任期比该候选人高呢?

    Raft中几乎大部分决策都和任期(term)有关,对方任期更高,则自己无论如何都需要投出选票,候选人还要转变成群众身份!!!

  4. 群众是如果决定给对方投票的,是对方任期大于自己的任期就投,还是直接按照先来后到呢?

    term!!! term!!! term!!!听到我的呼唤没,对于同一个任期的候选人,群众只有一张选票,可是出现更高任期的候选人,群众必须给出选票,一切以term为主!

以上这几个问题几乎都是论文中没有详细说明的地方,可能也是Raft并不容易理解的地方,像加粗的term一样,关注任期,以任期作为重要参考来决策。在选举的时候,就得确定一致性,也就是term的一致性,每个人的term都得是相同的。

特殊例子

举个例子,如果两个候选人同时重置超时,会出现什么情况呢?

首先是C、B作为候选人重置选举超时,但是C率先恢复,让自己的任期+1,并向A、B、D发出了请求投票:

H7b4602edbd3c4ac38dd000222bce0d26i

然后,A、B(候选人)、D全部投出了自己的选票,因为C的任期最高:

Hde2cfbd39af846c7ae31760437561228y

最后,C成为了领导人,并开始发送AppendEntries RPC维持自己的地位!

H705b906d92bb47d196e5263b5fba42b9x

以上内容部分参考Raft论文中文译文Raft 为什么是更易理解的分布式一致性算法、以及可视化Raft