選主
選舉算法
角色定義
這里的選主為什么提角色? 是因?yàn)椴煌巧谶x主中起到不同的作用.master的非voting_only
節(jié)點(diǎn)不但參與投票同時(shí)還可以參與競(jìng)選, master 的voting_only
角色僅投票不參與競(jìng)選,其余角色不參與.
支持的角色
master
data
data_content
data_hot
data_warm
data_cold
data_frozen
ingest
ml
remote_cluster_client
transform
如果不設(shè)置node.roles
則默認(rèn)有所有角色, 如果配置了,以配置的為準(zhǔn).
remote_cluster_client
跨集群搜索和副本角色
只有master角色才允許voting_only
高可用集群最少需要3個(gè)master
data角色如果分層的話,又可以分為
data_content,data_hot,data_warm,data_cold,或data_frozen
不同的層在存儲(chǔ)時(shí)間,是否壓縮,訪問性能等進(jìn)行差異化管理.以達(dá)到空間和性能的最優(yōu)化.
法定人數(shù)機(jī)制
. 法定人數(shù)一般大于半數(shù),主要目的是提高集群健壯性同時(shí)要避免腦裂問題.這個(gè)數(shù)值一般是多少? 一般
- 奇數(shù)投票節(jié)點(diǎn)
- n/2+1個(gè)quorum
正常情況quorum等于候選節(jié)點(diǎn)+投票節(jié)點(diǎn)之和
選舉完成之后提交集群狀態(tài)
選主協(xié)議
選主協(xié)議應(yīng)該包含至少4個(gè)部分
-
檢測(cè)
-
發(fā)起
-
選主核心邏輯(互斥和一致性)
-
發(fā)布狀態(tài)
先發(fā)起的會(huì)成功,如果同時(shí)發(fā)起則失敗.依據(jù)是什么? 時(shí)間戳?
為了避免選舉沖突每個(gè)節(jié)點(diǎn)發(fā)起選舉流程都是隨機(jī)調(diào)度.
檢測(cè)
一般提供兩種, 一種檢測(cè)master, 一種檢測(cè)node, 一般通過ping,默認(rèn)1s,連續(xù)失敗3次判定節(jié)點(diǎn)失效.
發(fā)起
當(dāng)檢測(cè)判定主節(jié)點(diǎn)失效則會(huì)發(fā)起投票
選主核心邏輯
如何避免沖突?
- 如果發(fā)現(xiàn)節(jié)點(diǎn)不是自己,則加入. 所以即使同時(shí)發(fā)起選舉也不影響,大家會(huì)加入相同的集群,除非發(fā)生腦裂分區(qū)等異常
如何避免腦裂?
- 檢查自己集群法定人數(shù)如果自己集群法定人數(shù)(過半),則放棄,重新加入其他集群.這個(gè)主要是避免腦裂
選舉常見問題
增減節(jié)點(diǎn)同步信息未完成發(fā)生選舉
如果增減節(jié)點(diǎn)同步信息未完成發(fā)生選舉,是否有不一致和集群可用性問題
投票設(shè)置
增減節(jié)點(diǎn)動(dòng)態(tài)調(diào)整
增減節(jié)點(diǎn)動(dòng)態(tài)調(diào)整投票配置,以增強(qiáng)集群的彈性
這個(gè)一般發(fā)生增減節(jié)點(diǎn)時(shí),通過自動(dòng)通信機(jī)制來實(shí)現(xiàn).
節(jié)點(diǎn)數(shù)
一般需要奇數(shù)
如果不是奇數(shù)它會(huì)取消一個(gè)節(jié)點(diǎn)的選舉權(quán)
奇數(shù)某些情況可以提高網(wǎng)絡(luò)分區(qū)可用性問題
比如4個(gè)節(jié)點(diǎn)集群, 會(huì)有3個(gè)候選節(jié)點(diǎn), 法定投票人數(shù)最少是2,那么一旦分區(qū)之后,至少有個(gè)一個(gè)分區(qū)包含2個(gè)節(jié)點(diǎn),這時(shí)候仍然是可用的
如果每個(gè)節(jié)點(diǎn)配置的集群期望節(jié)點(diǎn)數(shù)不一致會(huì)導(dǎo)致什么問題?
數(shù)據(jù)丟失.這種場(chǎng)景一般發(fā)生在初次啟動(dòng)時(shí), 已經(jīng)啟動(dòng)之后因?yàn)橛泄?jié)點(diǎn)發(fā)現(xiàn)協(xié)議,它會(huì)慢慢的讀取到正確的節(jié)點(diǎn).
對(duì)集群來說它自己沒法提供一個(gè)完全安全的引導(dǎo)啟動(dòng)配置, 即使所有節(jié)點(diǎn)的引導(dǎo)啟動(dòng)配置一致,也無法保證集群完全安全的啟動(dòng).比如這樣一個(gè)有4臺(tái)node的集群,他們通過自動(dòng)化同時(shí)啟動(dòng)很可能造成分區(qū).因?yàn)?個(gè)node,只能有奇數(shù)(3)個(gè)node有投票權(quán), 那么2個(gè)node投票就可以形成集群(如果是通過集群動(dòng)態(tài)調(diào)整投票節(jié)點(diǎn)的話, 如果你固定配置某個(gè)節(jié)點(diǎn)沒有投票權(quán)當(dāng)然可以避免)
所以quorum是集群?jiǎn)?dòng)的必選項(xiàng).
選主流程
選舉臨時(shí)Master->[本節(jié)點(diǎn)是Master?確人orelse加入]->啟動(dòng)NodeFD OR 啟動(dòng)MasterFD
為什么選舉臨時(shí)Master
需要足夠票數(shù)
臨時(shí)Master選舉流程
ping所有節(jié)點(diǎn)->獲取所有節(jié)點(diǎn)reposne+本節(jié)點(diǎn)也加入response->構(gòu)建兩個(gè)列表activeMaster和(活躍的Master節(jié)點(diǎn))
正常情況activeMaster只能有一個(gè),這里為什么是列表, 因?yàn)榭赡艽嬖诓灰恢虑闆r.并且構(gòu)建active master過程中如果節(jié)點(diǎn)不具備資格根據(jù)配置ignore_non_master_pings
會(huì)忽略.
另一個(gè)要維護(hù)的列表是masterCandidates
兩個(gè)列表構(gòu)建完成之后, 如果沒有active master則從候選master列表選擇進(jìn)行選舉
選舉臨時(shí)Master
它的選主邏輯很簡(jiǎn)單就是從節(jié)點(diǎn)找出版本最高的然后最小的節(jié)點(diǎn). 源碼對(duì)應(yīng)的方法是electMaster
public MasterCandidate electMaster(Collection<MasterCandidate> candidates) {
assert hasEnoughCandidates(candidates);
List<MasterCandidate> sortedCandidates = new ArrayList<>(candidates);
sortedCandidates.sort(MasterCandidate::compare);
return sortedCandidates.get(0);
}
// 取version最大及節(jié)點(diǎn)最小的作為主節(jié)點(diǎn)
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;
}
但是從源碼我們看出來, 它沒有判斷角色,其實(shí)候選master是需要對(duì)應(yīng)角色的. 這塊的邏輯是怎么樣的?
/** master nodes go before other nodes, with a secondary sort by id **/
private static int compareNodes(DiscoveryNode o1, DiscoveryNode o2) {
// 優(yōu)先選擇是master node的節(jié)點(diǎn)
if (o1.isMasterNode() && o2.isMasterNode() == false) {
return -1;
}
if (o1.isMasterNode() == false && o2.isMasterNode()) {
return 1;
}
// 如果都是或者都不是再比較節(jié)點(diǎn)id,取小的
return o1.getId().compareTo(o2.getId());
}
那么我們可能會(huì)有個(gè)疑問不具備master角色的節(jié)點(diǎn)為什么有資格參與競(jìng)選主節(jié)點(diǎn)呢? 其實(shí)這部分邏輯主要是為了列表排序,并不是真正的選主,選主邏輯會(huì)判斷它是否具備資格. 那為什么不在這里直接過濾呢?
我能回答的是,它有過濾但是沒有在這里過濾
ZenDiscovery#handleJoinRequest->NodeJoinController.ElectionContext#getPendingMasterJoinsCount
public synchronized int getPendingMasterJoinsCount() {
int pendingMasterJoins = 0;
for (DiscoveryNode node : joinRequestAccumulator.keySet()) {
// 這個(gè)邏輯是用來判定候選節(jié)點(diǎn)數(shù)是否達(dá)到法定人數(shù)的, 在這里排除掉了非master節(jié)點(diǎn), 但是如果非master節(jié)點(diǎn)依然在候選列表中
if (node.isMasterNode()) {
pendingMasterJoins++;
}
}
return pendingMasterJoins;
}
如果候選節(jié)點(diǎn)是自己
(1) 等待節(jié)點(diǎn)加入自己集群
(2) 超時(shí)重新選舉
(3) 成功發(fā)布通知
private void innerJoinCluster() {
...
// 如果臨時(shí)Master是本節(jié)點(diǎn)
if (transportService.getLocalNode().equals(masterNode)) {
final int requiredJoins = Math.max(0, electMaster.minimumMasterNodes() - 1); // we count as one
// 等待足夠多的具備Master資格的節(jié)點(diǎn)加入本節(jié)點(diǎn)(投票達(dá)到法定人數(shù)),以完成選舉。
nodeJoinController.waitToBeElectedAsMaster(
requiredJoins,
// 超時(shí)(默認(rèn)為30秒,可配置)后還沒有滿足數(shù)量的join請(qǐng)求,則選舉失敗,需要進(jìn)行新一輪選舉。
masterElectionWaitForJoinsTimeout,
new NodeJoinController.ElectionCallback() {
// 成功后發(fā)布新的clusterState。
@Override
public void onElectedAsMaster(ClusterState state) {
synchronized (stateMutex) {
joinThreadControl.markThreadAsDone(currentThread);
}
}
@Override
public void onFailure(Throwable t) {
...
}
}
);
} else {
...
}
}
如果不是自己
如果其他節(jié)點(diǎn)被選為Master:
(1) 停止接受節(jié)點(diǎn)加入自己集群請(qǐng)求
(2) 發(fā)起加入其他節(jié)點(diǎn)集群請(qǐng)求文章來源:http://www.zghlxwxcb.cn/news/detail-604603.html
(3)等待回復(fù)文章來源地址http://www.zghlxwxcb.cn/news/detail-604603.html
private void innerJoinCluster() {
...
if (transportService.getLocalNode().equals(masterNode)) {
...
} else {
// process any incoming joins (they will fail because we are not the master)
// 不再接受其他節(jié)點(diǎn)的join請(qǐng)求
nodeJoinController.stopElectionContext(masterNode + " elected");
// send join request
//向Master發(fā)送加入請(qǐng)求,并等待回復(fù)。超時(shí)時(shí)間默認(rèn)為1分鐘(可配置),如果遇到異常,則默認(rèn)重試3次(可配置)。這個(gè)步驟在joinElectedMaster方法中實(shí)現(xiàn)。
final boolean success = joinElectedMaster(masterNode);
// 最終當(dāng)選的Master會(huì)先發(fā)布集群狀態(tài),才確認(rèn)客戶的join請(qǐng)求,因此,joinElectedMaster返回代表收到了join請(qǐng)求的確認(rèn),并且已經(jīng)收到了集群狀態(tài)。本步驟檢查收到的集群狀態(tài)中的Master節(jié)點(diǎn)如果為空,或者當(dāng)選的Master不是之前選擇的節(jié)點(diǎn),則重新選舉。
synchronized (stateMutex) {
if (success) {
DiscoveryNode currentMasterNode = this.clusterState().getNodes().getMasterNode();
if (currentMasterNode == null) {
// Post 1.3.0, the master should publish a new cluster state before acking our join request. we now should have
// a valid master.
logger.debug("no master node is set, despite of join request completing. retrying pings.");
joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
} else if (currentMasterNode.equals(masterNode) == false) {
// update cluster state
joinThreadControl.stopRunningThreadAndRejoin("master_switched_while_finalizing_join");
}
joinThreadControl.markThreadAsDone(currentThread);
} else {
// failed to join. Try again...
joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
}
}
}
}
到了這里,關(guān)于elastic elasticsearch 源碼解析之選主選舉過程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!