ES 选举Master节点机制
ES采用主从模式架构,Master节点的选取对整个集群的可用性及数据一致性都起到了关键作用,下面介绍一下ES选取主节点的流程(版本6.1)
整体流程
选举临时Master节点,判断如果本节当选,则等待选票超过半数,成为真正的Master节点,如果本节点不是临时Master节点,则尝试加入集群,加入集群其实是投票的过程,整体流程如下:
1 选取临时节点
1.1 ping所有节点,获取节点列表fullPingResponses,并将自己添加到列表中
1.2 构建目前存在的master列表activeMasters
获取请求结果的所有节点的master节点
List<DiscoveryNode> activeMasters = new ArrayList<>();
for (ZenPing.PingResponse pingResponse : pingResponses) {
// We can't include the local node in pingMasters list, otherwise we may up electing ourselves without
// any check / verifications from other nodes in ZenDiscover#innerJoinCluster()
if (pingResponse.master() != null && !localNode.equals(pingResponse.master())) {
activeMasters.add(pingResponse.master());
}
}
1.3构建master候选列表masterCandidates
将ping获取的列表中,在启动时node.master true 的筛选出来,作为候选master
List<ElectMasterService.MasterCandidate> masterCandidates = new ArrayList<>();
for (ZenPing.PingResponse pingResponse : pingResponses) {
if (pingResponse.node().isMasterNode()) {
masterCandidates.add(new ElectMasterService.MasterCandidate(pingResponse.node(), pingResponse.getClusterStateVersion()));
}
}
2 选择出临时master
整体流程如下:
- 判断activeMasters是否为空,如果不为空从activeMasters中选取一个节点作为临时主节点;
public DiscoveryNode tieBreakActiveMasters(Collection<DiscoveryNode> activeMasters) {
return activeMasters.stream().min(ElectMasterService::compareNodes).get();
}
直接使用选取排序后最小的作为临时master,比较器的规则:
/** master nodes go before other nodes, with a secondary sort by id **/
private static int compareNodes(DiscoveryNode o1, DiscoveryNode o2) {
if (o1.isMasterNode() && !o2.isMasterNode()) {
return -1;
}
if (!o1.isMasterNode() && o2.isMasterNode()) {
return 1;
}
// 直接使用node的id进行比较
return o1.getId().compareTo(o2.getId());
}
- 如果
activeMasters
为空,则从候选列表masterCandidates
中选取一个作为临时主节点;
在masterCandidates
中选取主节点时,首先需要判断候选人数是否达到了半数以上,当满足半数以上时,开始选择主节点,选择主节点的规则比较简单:
public static int compare(MasterCandidate c1, MasterCandidate c2) {
// we explicitly swap c1 and c2 here. the code expects "better" is lower in a sorted
// list, so if c2 has a higher cluster state version, it needs to come first.
int ret = Long.compare(c2.clusterStateVersion, c1.clusterStateVersion);
if (ret == 0) {
ret = compareNodes(c1.getNode(), c2.getNode());
}
return ret;
}
先比较集群状态的版本,选择集群状态版本较高的作为临时master,如果相同,则按照和activeMasters中选取的方式一样取ID较小的作为临时Master;
确立Master或者加入集群
- 如果本节点被选为临时Master,等待(默认30s)足够多节点加入本节点(超过一半)后,完成选举,并发布新的clusterState
- 如果其他节点本选为临时Master节点,向Master节点发送加入集群的请求,等待(1分钟)回复,最终master会发布集群状态,并确认客户join请求;
如果以上处理失败,则重新开始新一轮的选举;
节点失效监测
- Master节点启动NodesFaultDetection定期监测加入集群的节点是否活跃;
- 非Master节点启动MasterFaultDetection定期监测Master节点是否活跃;
节点监测都是通过定期(1s)发送ping探测节点是否正常,如果超过3次,则开始处理节点离开事件;
NodesFaultDetection事件处理
检查集群是否达到了法定节点数(过半),如果不足,则放弃Master重新加入集群,这样做的目的是为了防止产生双主,例如集群中有5个节点[A,B,C,D,E],A为主节点,由于某种原因,集群网络出现分区[A,B],[C,D,E],这时候[C,D,E] 组成的分区监测不到主节点开始处理MasterFaultDetection重新选举主节点,假设选举C为主节点;由于A节点无法监测到[C,D,E]三个节点,开始处理NodesFaultDetection,这时候如果A所在分区如果不监测法定节点数,继续作为主节点;整个集群会出现两个主节点A,C;
MasterFaultDetection事件处理
监测到主节点离线后回重新监测法定节点数,并进行新一轮的选择;