本文是 MIT6.824 Lab-2A 涉及到的 Raft 算法的总结,主要涉及到
- Leader 的选举
- 心跳(不包括状态机日志复制)
其余部分将在后续做相应的实验的时候进行更新
什么是 Raft
Raft 算法是一种分布式一致性共识算法
什么是分布式一致性共识算法
在分布式系统理论中,有著名的 CAP 理论(Consistency-Availability-Partition tolerance Theory)
- C:Consitency,一致性。该项强调数据的正确性. 具体而言,每次读操作,要么读到最新,要么读失败. 这要求整个分布式系统像是一个不可拆分的整体,写操作作用于集群像作用于单机一样,具有广义的"原子性".
- A:Availability,可用性。该项站在使用者的角度,强调使用服务的体验.客户端的请求能够得到响应,不发生错误,也不能出现过长的等待时间.
- P:Partition tolerance,分区容错性。分区容错性强调的是,在网络环境不可靠的背景下,整个系统仍然是正常运作的,不至于出现系统崩溃或者秩序混乱的局面.
CAP 理论强调的是,一个系统中,C、A、P 三项性质至多只能满足其二,即每个系统依据其架构设计会具有 CP、AP 或者 CA 的倾向性.
分布式一致性共识算法指的是在分布式系统中,使得所有节点对同一份数据的认知能够达成共识的算法.
可以看到,不论是命名还是概述,都在突出其实现目标在于 C,即数据一致性. 然而,在 1.5 小节中我们已谈及,倘若基于写请求 + 数据同步串行化的方式进行实施,实际上是可以满足强 C 的,但是对应的 A 就会破坏得支离破碎.
因此,分布式一致性共识算法,实际上是在基于各种精妙的算法机制,能够在尽可能少地牺牲 C 的基础之上,将 A 提升到尽可能高的水平.
我们今天的主角 Raft 算法扮演的正是这样一个角色.
Raft 的一些概念
一主多从
在 raft 算法中节点会分为 一个 Leader ,和 多个 Follower ,(这里暂时忽略 Candidate)其中
- Leader 负责处理客户端的写请求 ,复制日志 (将数据同步给 Follower 节点),发布心跳(维持其领导地位)
- Follower 负责响应客户端的读请求 ,接收Leader发送的日志项,并将其存储在本地日志中,保持与Leader相同的日志顺序 ,选举投票
多数派原则
多数派原则指的是,系统的决断无需全员参与 ,多数派达成的共识即可视为整个系统的答复。
举个例子:假设一个集群存在 5 个节点。如果客户端发送了一个写请求给 Leader。在 Raft 算法中,由于多数派原则的存在,那么这个写入的日志只需要被写入到集群中的多数,也即 3 个节点中(包括 Leader),就可以认为该数据已经被成功写入。
多数派原则将会贯穿 raft 算法的始终,例如我们下面要介绍的选举 、日志复制 等等
其他概念在 Lab-2A 中暂时还不是很重要,我们将在另外的文章中提及。
任期(Term)
在Raft共识算法中,Term(任期)是一个重要的概念,用于标识系统中的不同时间段。每个任期都有一个唯一的正整数标识,它在整个系统中用于区分不同的时期。
- 一个Term内只能有一个Leader,当一个节点成为Leader时,它的Term会增加。
- 任期的引入有助于防止过时信息的影响。在Raft中,节点在进行投票、处理心跳等操作时,会比较Term的大小,只有当Term更大的信息才会被接受,从而防止过时的信息对系统造成不一致性。
总体而言,Raft中的Term是一种用于标识时间段和协调节点之间通信的机制,有助于确保系统的一致性和正确性。每次发生选举时,都会引入一个新的Term,确保系统在不同的时间段有清晰的状态。
Raft 算法中的选举
选举在干些什么?
- 前面我们提到,在 Raft 算法中,有 Leader 和 Follower 的区分,而且 Leader 是必须存在且唯一的。
- 那么 Raft 算法的选举就是要保证在每个时间段中,集群中都有唯一的 Leader 存在 ,并且在网络分区、节点故障或其他异常情况下,系统仍然能够维持一致性。当Raft系统中的Leader节点出现问题(例如崩溃或无法正常通信)时,其他节点会通过一轮选举来选举新的Leader。
选举的过程
Leader 是怎么上任的
在节点初始化时,每个节点都会被初始化为 Follower 。
在 Raft 算法中,有两个时间来控制选举,第一个是 election timeout
, election timeout
是指追随者在成为候选人之前等待的时间。election timeout
被随机分配为150毫秒到300毫秒之间。
关于"
election timeout
被随机分配为150毫秒到300毫秒",这里的随机目的是什么,为什么不给出一个具体的值?
- 引入随机的
election timeout
是为了避免出现多个节点同时发起选举的情况,从而降低冲突的概率。如果所有的节点都在相同的固定时间间隔内成为候选人,它们可能会同时发起选举并请求投票。这可能导致投票分散,难以达到选举的多数派要求。- 通过引入随机性,每个节点的
election timeout
在一个范围内波动,就会导致节点在不同的时间点成为候选人,减少了竞争的激烈程度。这样,系统中的节点更有可能依次成为候选人,并且每个节点的选举时间点会有所不同。
-
当节点被初始化之后,就会启动一个定时器,定时器被触发,也就是
election timeout
到期之后,Follower
就会变成Candidate
(候选人) ,并且开启一个新的任期(term
),此时选举便正式开始了**关于 Candidate(候选人):**在 Raft 算法中,Follower 要成为 Leader 必须先成为一个 Candidate ,Candidate 会向其他节点发送投票请求,请求其他节点投票支持自己成为新的 Leader。如果一个 Candidate 获得大多数节点的选票,它将成为新的 Leader
-
Candidate
开启一个新的 term 之后干的第一件事情,就是把自己的那一票投给自己。紧接着,它会发送Request Vote
(投票请求)给集群内的其他节点,请求其他节点将票投给自己。 -
如果收到
Request Vote
的节点在当前任期内还没有把票投出去,那么他会把票投给当前候选人。并且重置自己的election timeout
。这里要说明一下投票响应的规则:
- 如果接收到的投票请求中的term小于等于节点当前的term,节点会拒绝投票。
- 如果节点还没有为当前term投过票,它会投票给候选人。
- 如果节点已经投过票给其他候选人,它会拒绝再次投票。 至于为什么要制定这样的规则,请参考论文
-
一旦
Candidate
收到多数派节点的选票,那么他就会成为新的Leader
值得注意的是,即使每个节点的
election timeout
都是随机的,但也有可能出现两个节点同时开始选举的情况,这时还是会出现两个节点都无法拿到多数派选票,无法成功上任。 针对这种情况,Raft 采取的措施是节点直接等待一轮新的选举开始。
Leader 怎么维持其领导地位?它要是挂了怎么办?
前面我们提到,"在 Raft 算法中,有两个时间来控制选举"。我们一个知道其中一个是 election timeout
,那么另外一个就是 heartbeat timeout
-
在
Candidate
当选为Leader
之后,该节点就会开始维护一个心跳 ,每次触发心跳,Leader
就会发送一个Append Entries
给其他节点。 -
Follower
接收到Append Entries
会重置自身的election timeout
,防止在Leader
没有出现异常的情况下开启新一轮的选举。值得注意的是,在下面这几种情况中,Follower
不能重置election timeout
。- 心跳发起者的任期已经过时了,也就是
args.PrevLogTerm < rf.currentTerm
,这种情况可能出现在出现网络屏障后恢复,此时已经有新的Leader
出现,例如下图中,AB 和 CDF 中间出现了网络屏障,此时 CDF 中选举出了新的 Leader D.那么当网络屏障消失之后,B 发送心跳请求给 C/D/F 时,会发现自己的任期已经落后了,此时 A 自己卸任成文Follower
- 心跳发起者的任期已经过时了,也就是

关于
Append Entries
的作用:
日志复制: 当领导者产生新的日志条目时,它将这些新条目包含在 "Append Entries" 消息中发送给跟随者。跟随者接收到这些消息后,会将领导者的日志条目追加到自己的日志中,从而保持日志的一致性。
心跳功能: "Append Entries" 消息也用作心跳。在Raft中,领导者定期发送空的 "Append Entries" 消息给跟随者,起到一种心跳的作用。如果跟随者在一定时间内没有收到领导者的心跳消息,就可能认为领导者已经失效,触发新一轮的选举。 这里我们暂时只讨论它作为心跳的功能。
-
如果
Leader
接收到Follower
返回的信息,发现自己过时了,那么需要切换自己的角色为Follower
-
如果
Leader
接收到Follower
返回的正常信息,那么只需要正常的等待发送下一轮心跳就可以了。(解决了"Leader 怎么维持其领导地位"的问题) -
如果
Follower
在一个election timeout
周期内,都没有收到任何心跳请求,那么Follower
就会成为Candidate
参加竞选.(解决了"它要是挂了怎么办"的问题)
因此在 Raft 算法中
election timeout > heartbeat timeout
写在最后
- 至此,Raft算法中的选举部分我们就讲了个七七八八,至于Lab-2A的具体实现细节,将会在下一篇文章中讲到.
- 本文只是很粗糙的讲了一下选举的过程,里面很多细节都没详细展开,比如:
- 为什么节点的投票规则是这样规定的?
- 为什么是多数派原则,而不是等全部节点通过?
- 读者可以自己在原始论文中找到这些答案.
- 同样的,我们也没有对 Raft 算法下的外部请求链路,状态机,两阶段提交,日志索引,预写日志等做出解释,这将在后面的 lab 中给出.
参考资料
- Raft 原始论文:pdos.csail.mit.edu/6.824/paper...
- Raft 论文翻译:github.com/maemual/raf...
- Raft 可视化网站:thesecretlivesofdata.com/raft/