Raft 论文地址:https://ramcloud.atlassian.ne... 算法
Raft论文中分为三块:安全
本文中主要介绍领导人选举
服务器
Raft中的节点有三种状态:网络
Leader
Follower
Candidate
每个节点都是一个状态机,Raft会根据当前的心跳,任期等状态来进行状态的迁移转化,就以下图所示:并发
首先,在Raft节点启动的时候,全部任务都是Follower
状态, 由于此时没有Leader
,全部Follower
都在固定的超时时间内都收不到来自Leader
的心跳,从而变成了Candidate
状态,开始选举Leader
spa
当节点处于Candidate
状态的时候,会并发的向全部的节点发出请求投票请求RequestVote
(后面章节会向详细介绍),在Candidate
状态下,节点可能会发生三种状态的迁移变化:.net
N/2+1
,那么选取超时,进入下一轮选举Leader
:若是选举过程当中收到大于N/2+1
数量的节点的投票,那么选举成功,当前的节点成为新的Leader
Follower
:若是选举过程当中收到来及其余节点的Leader
心跳,或者是请求投票响应的Term
大于当前的节点Term
,那么说明有新任期的Leader
若是节点选举成功,成为了Leader
,那么Leader
将会在固定周期内发送心跳到全部的节点,可是若是心跳请求收到的响应的Term
大于当前节点的Term
,那么当前节点的就会成为Follower
。好比Leader
节点的网络不稳定,掉线了一段时间,网络恢复的时候,确定有其余节点被选为了新的Leader
,可是当前节点在掉线的时候并无发现其余节点选为Leader
,仍然发送心跳给其余节点,其余节点就会把当前的新的Term
响应给已通过时的Leader
,从而转变成Follower
日志
整个集群必需要在丢包,乱序,延时等诸多不稳定因素的状况下,可以选举出惟一一个Leader
code
就如上文中提到的,若是Follower
在必定时间内没有收到心跳请求,那么将会切换到Candidate
状态,开始一轮新的选取,选举过程当中会向集群中的全部节点发送请求投票的RPCblog
RPC请求参数:
term
:当前候选人的任期号candidateId
:候选人的IdlastLogIndex
:候选人的最后日志条目索引值lastLogTerm
:候选人的最后日志条目的任期号其中lastLogIndex
和lastLogTerm
用来判断候选人的日志是否和服务器的日志同样新(后文中会解释),必需要至少同样新才能投票。
RPC响应值:
term
:被请求节点的任期号voteGranted
:是否赞成投票给候选人若是Leader
发生异常,那么基本上全部的Follower
在同一时间切换为Candidate
,并同时发出请求投票的RPC,那么就有可能致使选票被均衡的瓜分,从而须要从新发起新一轮的投票。为了不选票被瓜分的问题,选举超时的是能够能够从一个固定的区间(例如150-300
毫秒)随机选择。
判断当前的Term
的和请求投票参数中的Term
:
Term
> 请求投票参数中的Term
,那么拒绝投票(设置voteGranted
为false
),并返回当前的Term
Term
为请求投票参数中的Term
, 并将自身状态切换成Follower
检测当前节点的投票状态:
voteGranted
为false
), 由于一个节点在一个任期内不能同时投票给多个节点检测候选人的日志是否至少比当前节点的日志新,经过比较候选人的lastLogIndex
和lastLogTerm
和当前节点的日志,确保新选举出来的Leader
不会丢失已经提交的日志:
votedGranted
为true
),并成为Follower
voteGranted
为false
)每个候选人在每个任期内都会发出一轮投票请求,若是在指定时间内,收到大于N/2+1
个节点的赞成投票的响应,那么说明投票成功,晋升为Leader
由于在整个投票过程当中,假设网络是不稳定的,那么就有可能致使投票请求和请求的响应丢失,乱序,延时等,从而致使收到和当前任期不相匹配的响应,因此若是收到和当前任期不匹配的响应,那么就直接丢弃不处理。
完整的处理流程以下:
检查响应的Term
是否大于当前候选人的Term
:
Leader
被选举出来,那么就把当前节点从Candidate
切换为Follower
状态,并更新当前节点的Term
检查响应的Term
是否和当前的节点的Term
是否相等:
检查响应是否赞成投票:
N/2+1
,那么就切换为Leader
Leader
的日志至少要比Follower
的日志新从上文的请求投票RPC的处理流程中得知,Leader
不是随便选一个节点均可以成为的,若是候选人不知足要求,那么其余节点就不会给候选人投票。
若是集群中的任何一个节点不通过判断就能成为Leader
,那么将会发生什么?这种状况可能致使已经被提交的日志被覆盖,若是状态机已经Apply了被覆盖的日志,将会致使不一致的结果。因此为了选举的安全性,Raft
添加了如下的限制:
Leader
不会覆盖本身的任何日志,Follower
严格按照Leader
的日志进行复制(必要时强行覆盖)Leader
的时候,Candidate
的日志至少要比当前节点新(这个“新”稍后解释),不然就拒绝投票;由于已经提交的日志确定是存在大于等于N/2+1
个节点上的,而投票至少也须要N/2+1
个节点赞成,因此整个投票过程当中确定会有包含有全部已经提交日志的节点存在的。上文中的“新”就是:即当前的任期和候选人的任期相同,且候选人的日志长度比当前的日志长度 或者 候选人的任期比比当前节点的任期高