1、Nacos集群选举策略
在Raft协议中,节点有三种角色:
- Leader:负责接收客户端的请求
- Candidate:用于选举Leader的一种角色
- Follower:负责响应来自Leader或者Candidate的请求
选举分为两个阶段:
- 服务启动的时候
- leader挂了的时候
所有节点启动的时候,都是follower状态。 如果在一段时间内如果没有收到leader的心跳(可能是没有leader,也可能是leader挂了),那么follower会变成Candidate。然后发起选举,选举之前,会增加term,这个term和zookeeper中的epoch的道理是一样的。
follower会投自己一票,并且给其他节点发送票据vote,等到其他节点回复。
在这个过程中,可能出现几种情况
- 收到过半的票数通过,则成为leader
- 被告知其他节点已经成为leader,则自己切换为follower
- 一段时间内没有收到过半的投票,则重新发起选举
约束条件:
- 在任一term中,单个节点最多只能投一票
2、Nacos Raft源码分析
2.1、RaftCore.init()
Nacos Server在启动的时候会调用RaftCore.init()方法进行集群选举操作和节点之间的心跳机制
/**
* @author nacos
*/
@Component
public class RaftCore {
@PostConstruct
public void init() throws Exception {
Loggers.RAFT.info("initializing Raft sub-system");
executor.submit(notifier);
long start = System.currentTimeMillis();
raftStore.loadDatums(notifier, datums);
setTerm(NumberUtils.toLong(raftStore.loadMeta().getProperty("term"), 0L));
Loggers.RAFT.info("cache loaded, datum count: {}, current term: {}", datums.size(), peers.getTerm());
while (true) {
if (notifier.tasks.size() <= 0) {
break;
}
Thread.sleep(1000L);
}
initialized = true;
Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start));
//节点选举
GlobalExecutor.registerMasterElection(new MasterElection());
//集群节点的心跳机制
GlobalExecutor.registerHeartbeat(new HeartBeat());
Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}",
GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS);
}
}
在init()方法中,使用GlobalExecutor.registerMasterElection(new MasterElection());方法来进行选举操作;
registerMasterElection()方法中,启动了一个定时任务去执行MasterElection里面的操作;接下来看MasterElection里面的逻辑:
2.2、new MasterElection()
public class MasterElection implements Runnable {
@Override
public void run() {
try {
if (!peers.isReady()) {
return;
}
//获取本机RaftPeer信息
RaftPeer local = peers.local();
local.leaderDueMs -= GlobalExecutor.TICK_PERIOD_MS;
if (local.leaderDueMs > 0) {
return;
}
// reset timeout
//重置选举超时时间和发送心跳时间
local.resetLeaderDue();
local.resetHeartbeatDue();
//发送选票信息到其他nacos节点
sendVote();
} catch (Exception e) {
Loggers.RAFT.warn("[RAFT] error while master election {}", e);
}
}
在new MasterElection()线程中,首先会获取本机nacos节点的RaftPeer信息&#x