Leader election
选举触发
当一个Follower一段时间内没有收到来自于Leader或者Candidate的消息时,该Follower会转化成Candidate进行一次选举:
触发选举时,该Candidate做的事情:
- currentTerm++(自身任期号+1);
- votedFor = me(给自己投票);
- resetElectTimer (重置定时器);
- 给除自己的所有server发送RequestVote请求;
这里会涉及到的超时时间有:
- base_election_timeout + rand_time
加上一个随机偏移,是为了防止多个Follower同时Candidate导致瓜分选票的概率。因此选举超时间可能是在一个区间(例如150 ~ 300ms) - 发送RPC会有一个RPCTimeout;
论文在后续章节讨论了对时间性的要求:
消息广播时间 << 选举超时时间 << 系统平均故障时间
RPCs需要对方将信息持久化到存储中,广播时间大约是0.5ms ~ 20ms(取决于存储的技术),因此选举超时时间可能在10ms ~ 500ms之间。
等待选举结果
在并行发送完RequestVote RPC后,会有三种结果
赢得选举
Candidate发送的RequestVote包含了自身的term,集群中每个server针对这个term最多只会投出一张选票,按照先来先得的原则;
额外的限制: RequestVote RPC中包含了Candidate的日志信息,投票人会拒绝那些日志没有自己新的RequestVote
接受者如果发现RequestVote的term比自己小的话(term < currentTerm
),会投反对票;
接受者在这个term还没有投过票的话(votedFor = nil
),就会赞成票;
Candidate如果赢得了大多数的选票的话(Election Safety),就会当选Leader,同时向其他的server发送心跳来阻止其他节点的选举触发。
收到其他节点的AppendEntry
等待期间,Candidate可能会收到其他节点发送过来的AppendEntry,该AppendEntry声明了该节点为Leader。
此时如果:
AppendEntry.term >= currentTerm
的话,承认这个Leader的地位,自己转化为Follower
AppendEntry.term < currentTerm
的话,返回false,拒绝这次RPC;
无人当选
这种情况可能发生在选票瓜分的情况下,此时每个Candidate都会再次election timeout,触发新一次的选举。(如上所说,增加了随机时间偏移)
simple example
example1
三节点初始状态:
server1
election timeout = 150ms
server2
election timeout = 150ms
server3
election timeout = 200ms
三者都是Follower;
150ms后:
server1超时,server1.currentTerm = 1, server1.votedFor = server1,
server1.elect_timeout rand update to 100s;
server2超时,server2.currentTerm = 1, server2.votedFor = server2,
server2.elect_timeout rand update to 200s
假设server3先收到server1的RequestVote, 此时server3.currentTerm = 0, 投票给server1;
紧接着收到了server2的RequestVote,此时因为Term=1任期已经投过票,因此拒绝投票。
最终server1当选Leader。
example2
五节点初始状态:
server1
election timeout = 150ms
server2
election timeout = 150ms
server3
election timeout = 150ms
server4
election timeout = 200ms
server5
election timeout = 300ms
150ms后:
server1超时,server1.currentTerm = 1, server1.votedFor = server1,
server1.elect_timeout rand update to 100s;
server2超时,server2.currentTerm = 1, server2.votedFor = server2,
server2.elect_timeout rand update to 200s
server3超时,server3.currentTerm = 1, server3.votedFor = server3,
server3.elect_timeout rand update to 300s
假设server4投票给server1;server5投票给server2
此时选票被瓜分,无Leader当选。
再经历100s后:
server1超时,server1.currentTerm = 2, server1.votedFor = server1,
此时其他的server都没有超时,因此都会投票server1发送的term=2的RequestVote。
最终,经过两轮election timeout,server1当选。