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事件處理
監測到主節點離線后回重新監測法定節點數,並進行新一輪的選擇;