在上一篇文章当中,我们讲解了NodeImpl在init方法里面会初始化话的动作,选举也是在这个方法里面进行的,这篇文章来从这个方法里详细讲一下选举的过程。
由于我这里介绍的是如何实现的,所以请大家先看一下原理:SOFAJRaft 选举机制剖析 | SOFAJRaft 实现原理
文章比较长,我也慢慢的写了半个月时间~
选举过程分析我在这里只把有关选举的代码列举出来,其他的代码暂且忽略
NodeImpl#init
在这个init方法里面会初始化三个计时器是和选举有关的:
voteTimer:这个timer负责定期的检查,如果当前的state的状态是候选者(STATE_CANDIDATE),那么就会发起选举
electionTimer:在一定时间内如果leader没有与 Follower 进行通信时,Follower 就可以认为leader已经不能正常担任leader的职责,那么就会进行选举,在选举之前会先发起预投票,如果没有得到半数以上节点的反馈,则候选者就会识趣的放弃参选。所以这个timer负责预投票
stepDownTimer:定时检查是否需要重新选举leader,如果当前的leader没有获得超过半数的Follower响应,那么这个leader就应该下台然后重新选举。
RepeatedTimer的分析我已经写好了:2. SOFAJRaft源码分析—JRaft的定时任务调度器是怎么做的?
我们先跟着init方法的思路往下看,一般来说this.conf里面装的是整个集群的节点信息,是不会为空的,所以会调用stepDown,所以先从这个方法看起。
leader下台 private void stepDown(final long term, final boolean wakeupCandidate, final Status status) { LOG.debug("Node {} stepDown, term={}, newTerm={}, wakeupCandidate={}.", getNodeId(), this.currTerm, term, wakeupCandidate); //校验一下当前节点的状态是否有异常,或正在关闭 if (!this.state.isActive()) { return; } //如果是候选者,那么停止选举 if (this.state == State.STATE_CANDIDATE) { //调用voteTimer的stop方法 stopVoteTimer(); //如果当前状态是leader或TRANSFERRING } else if (this.state.compareTo(State.STATE_TRANSFERRING) <= 0) { //让启动的stepDownTimer停止运作 stopStepDownTimer(); //清空选票箱中的内容 this.ballotBox.clearPendingTasks(); // signal fsm leader stop immediately if (this.state == State.STATE_LEADER) { //发送leader下台的事件给其他Follower onLeaderStop(status); } } // reset leader_id //重置当前节点的leader resetLeaderId(PeerId.emptyPeer(), status); // soft state in memory this.state = State.STATE_FOLLOWER; //重置Configuration的上下文 this.confCtx.reset(); updateLastLeaderTimestamp(Utils.monotonicMs()); if (this.snapshotExecutor != null) { //停止当前的快照生成 this.snapshotExecutor.interruptDownloadingSnapshots(term); } //设置任期为大的那个 // meta state if (term > this.currTerm) { this.currTerm = term; this.votedId = PeerId.emptyPeer(); //重设元数据信息保存到文件中 this.metaStorage.setTermAndVotedFor(term, this.votedId); } if (wakeupCandidate) { this.wakingCandidate = this.replicatorGroup.stopAllAndFindTheNextCandidate(this.conf); if (this.wakingCandidate != null) { Replicator.sendTimeoutNowAndStop(this.wakingCandidate, this.options.getElectionTimeoutMs()); } } else { //把replicatorGroup里面的所有replicator标记为stop this.replicatorGroup.stopAll(); } //leader转移的时候会用到 if (this.stopTransferArg != null) { if (this.transferTimer != null) { this.transferTimer.cancel(true); } // There is at most one StopTransferTimer at the same term, it's safe to // mark stopTransferArg to NULL this.stopTransferArg = null; } //启动 this.electionTimer.start(); }一个leader的下台需要做很多交接的工作:
如果当前的节点是个候选人(STATE_CANDIDATE),那么这个时候会让它暂时不要投票
如果当前的节点状态是(STATE_TRANSFERRING)表示正在转交leader或是leader(STATE_LEADER),那么就需要把当前节点的stepDownTimer这个定时器给关闭
如果当前是leader(STATE_LEADER),那么就需要告诉状态机leader下台了,可以在状态机中对下台的动作做处理
重置当前节点的leader,把当前节点的state状态设置为Follower,重置confCtx上下文
停止当前的快照生成,设置新的任期,让所有的复制节点停止工作
启动electionTimer