摘要: ES目前是最流行的開源分佈式搜索引擎系統,其使用Lucene做爲單機存儲引擎並提供強大的搜索查詢能力。學習其搜索原理,則必須瞭解Lucene,而學習ES的架構,就必須瞭解其分佈式如何實現,而一致性是分佈式系統的核心之一。html
前言
「Elasticsearch分佈式一致性原理剖析」系列將會對Elasticsearch的分佈式一致性原理進行詳細的剖析,介紹其實現方式、原理以及其存在的問題等(基於6.2版本)。 node
ES目前是最流行的開源分佈式搜索引擎系統,其使用Lucene做爲單機存儲引擎並提供強大的搜索查詢能力。學習其搜索原理,則必須瞭解Lucene,而學習ES的架構,就必須瞭解其分佈式如何實現,而一致性是分佈式系統的核心之一。
本篇將介紹ES的集羣組成、節點發現與Master選舉,錯誤檢測與擴縮容相關的內容。ES在處理節點發現與Master選舉等方面沒有選擇Zookeeper等外部組件,而是本身實現的一套,本文會介紹ES的這套機制是如何工做的,存在什麼問題。本文的主要內容以下:算法
首先,一個Elasticsearch集羣(下面簡稱ES集羣)是由許多節點(Node)構成的,Node能夠有不一樣的類型,經過如下配置,能夠產生四種不一樣類型的Node:api
conf/elasticsearch.yml: node.master: true/false node.data: true/false
四種不一樣類型的Node是一個node.master和node.data的true/false的兩兩組合。固然還有其餘類型的Node,好比IngestNode(用於數據預處理等),不在本文討論範圍內。安全
當node.master爲true時,其表示這個node是一個master的候選節點,能夠參與選舉,在ES的文檔中常被稱做master-eligible node,相似於MasterCandidate。ES正常運行時只能有一個master(即leader),多於1個時會發生腦裂。服務器
當node.data爲true時,這個節點做爲一個數據節點,會存儲分配在該node上的shard的數據並負責這些shard的寫入、查詢等。session
此外,任何一個集羣內的node均可以執行任何請求,其會負責將請求轉發給對應的node進行處理,因此當node.master和node.data都爲false時,這個節點能夠做爲一個相似proxy的節點,接受請求並進行轉發、結果聚合等。架構
上圖是一個ES集羣的示意圖,其中Node_A是當前集羣的Master,Node_B和Node_C是Master的候選節點,其中Node_A和Node_B同時也是數據節點(DataNode),此外,Node_D是一個單純的數據節點,Node_E是一個proxy節點。併發
到這裏,咱們提一個問題,供讀者思考:一個ES集羣應當配置多少個master-eligible node,當集羣的存儲或者計算資源不足,須要擴容時,新擴上去的節點應該設置爲什麼種類型?app
Node啓動後,首先要經過節點發現功能加入集羣。ZenDiscovery是ES本身實現的一套用於節點發現和選主等功能的模塊,沒有依賴Zookeeper等工具,官方文檔:
https://www.elastic.co/guide/...
簡單來講,節點發現依賴如下配置:
conf/elasticsearch.yml:
discovery.zen.ping.unicast.hosts: [1.1.1.1, 1.1.1.2, 1.1.1.3]
這個配置能夠看做是,在本節點到每一個hosts中的節點創建一條邊,當整個集羣全部的node造成一個聯通圖時,全部節點均可以知道集羣中有哪些節點,不會造成孤島。
官方推薦這裏設置爲全部的master-eligible node,讀者能夠想一想這樣有何好處:
It is recommended that the unicast hosts list be maintained as the list of master-eligible nodes in the cluster.
Master選舉
上圖是一個ES集羣的示意圖,其中Node_A是當前集羣的Master,Node_B和Node_C是Master的候選節點,其中Node_A和Node_B同時也是數據節點(DataNode),此外,Node_D是一個單純的數據節點,Node_E是一個proxy節點。
到這裏,咱們提一個問題,供讀者思考:一個ES集羣應當配置多少個master-eligible node,當集羣的存儲或者計算資源不足,須要擴容時,新擴上去的節點應該設置爲什麼種類型?
Node啓動後,首先要經過節點發現功能加入集羣。ZenDiscovery是ES本身實現的一套用於節點發現和選主等功能的模塊,沒有依賴Zookeeper等工具,官方文檔:
https://www.elastic.co/guide/...
簡單來講,節點發現依賴如下配置:
conf/elasticsearch.yml:
discovery.zen.ping.unicast.hosts: [1.1.1.1, 1.1.1.2, 1.1.1.3]
這個配置能夠看做是,在本節點到每一個hosts中的節點創建一條邊,當整個集羣全部的node造成一個聯通圖時,全部節點均可以知道集羣中有哪些節點,不會造成孤島。
官方推薦這裏設置爲全部的master-eligible node,讀者能夠想一想這樣有何好處:
It is recommended that the unicast hosts list be maintained as the list of master-eligible nodes in the cluster.
上面提到,集羣中可能會有多個master-eligible node,此時就要進行master選舉,保證只有一個當選master。若是有多個node當選爲master,則集羣會出現腦裂,腦裂會破壞數據的一致性,致使集羣行爲不可控,產生各類非預期的影響。
爲了不產生腦裂,ES採用了常見的分佈式系統思路,保證選舉出的master被多數派(quorum)的master-eligible node承認,以此來保證只有一個master。這個quorum經過如下配置進行配置:
conf/elasticsearch.yml: discovery.zen.minimum_master_nodes: 2
這個配置對於整個集羣很是重要。
加粗文字1 master選舉誰發起,何時發起?
master選舉是由master-eligible節點發起,當一個master-eligible節點發現知足如下條件時發起選舉:
該master-eligible節點的當前狀態不是master。
該master-eligible節點經過ZenDiscovery模塊的ping操做詢問其已知的集羣其餘節點,沒有任何節點鏈接到master。
包括本節點在內,當前已有超過minimum_master_nodes個節點沒有鏈接到master。
總結一句話,即當一個節點發現包括本身在內的多數派的master-eligible節點認爲集羣沒有master時,就能夠發起master選舉。
2 當須要選舉master時,選舉誰?
首先是選舉誰的問題,以下面源碼所示,選舉的是排序後的第一個MasterCandidate(即master-eligible node)。
public MasterCandidate electMaster(Collection<MasterCandidate> candidates) { assert hasEnoughCandidates(candidates); List<MasterCandidate> sortedCandidates = new ArrayList<>(candidates); sortedCandidates.sort(MasterCandidate::compare); return sortedCandidates.get(0); }
那麼是按照什麼排序的?
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;
}
如上面源碼所示,先根據節點的clusterStateVersion比較,clusterStateVersion越大,優先級越高。clusterStateVersion相同時,進入compareNodes,其內部按照節點的Id比較(Id爲節點第一次啓動時隨機生成)。
總結一下:
當clusterStateVersion越大,優先級越高。這是爲了保證新Master擁有最新的clusterState(即集羣的meta),避免已經commit的meta變動丟失。由於Master當選後,就會以這個版本的clusterState爲基礎進行更新。(一個例外是集羣所有重啓,全部節點都沒有meta,須要先選出一個master,而後master再經過持久化的數據進行meta恢復,再進行meta同步)。
當clusterStateVersion相同時,節點的Id越小,優先級越高。即老是傾向於選擇Id小的Node,這個Id是節點第一次啓動時生成的一個隨機字符串。之因此這麼設計,應該是爲了讓選舉結果儘量穩定,不要出現都想當master而選不出來的狀況。
3 怎麼算選舉成功?
當一個master-eligible node(咱們假設爲Node_A)發起一次選舉時,它會按照上述排序策略選出一個它認爲的master。
假設Node_A選Node_B當Master:
Node_A會向Node_B發送join請求,那麼此時:
(1) 若是Node_B已經成爲Master,Node_B就會把Node_A加入到集羣中,而後發佈最新的cluster_state, 最新的cluster_state就會包含Node_A的信息。至關於一次正常狀況的新節點加入。對於Node_A,等新的cluster_state發佈到Node_A的時候,Node_A也就完成join了。
(2) 若是Node_B在競選Master,那麼Node_B會把此次join看成一張選票。對於這種狀況,Node_A會等待一段時間,看Node_B是否能成爲真正的Master,直到超時或者有別的Master選成功。
(3) 若是Node_B認爲本身不是Master(如今不是,未來也選不上),那麼Node_B會拒絕此次join。對於這種狀況,Node_A會開啓下一輪選舉。
假設Node_A選本身當Master:
此時NodeA會等別的node來join,即等待別的node的選票,當收集到超過半數的選票時,認爲本身成爲master,而後變動cluster_state中的master node爲本身,並向集羣發佈這一消息。
有興趣的同窗能夠看看下面這段源碼:
if (transportService.getLocalNode().equals(masterNode)) { final int requiredJoins = Math.max(0, electMaster.minimumMasterNodes() - 1); // we count as one logger.debug("elected as master, waiting for incoming joins ([{}] needed)", requiredJoins); nodeJoinController.waitToBeElectedAsMaster(requiredJoins, masterElectionWaitForJoinsTimeout, new NodeJoinController.ElectionCallback() { @Override public void onElectedAsMaster(ClusterState state) { synchronized (stateMutex) { joinThreadControl.markThreadAsDone(currentThread); } } @Override public void onFailure(Throwable t) { logger.trace("failed while waiting for nodes to join, rejoining", t); synchronized (stateMutex) { joinThreadControl.markThreadAsDoneAndStartNew(currentThread); } } } ); } else { // process any incoming joins (they will fail because we are not the master) nodeJoinController.stopElectionContext(masterNode + " elected"); // send join request final boolean success = joinElectedMaster(masterNode); 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); }
按照上述流程,咱們描述一個簡單的場景來幫助你們理解:
假如集羣中有3個master-eligible node,分別爲Node_A、 Node_B、 Node_C, 選舉優先級也分別爲Node_A、Node_B、Node_C。三個node都認爲當前沒有master,因而都各自發起選舉,選舉結果都爲Node_A(由於選舉時按照優先級排序,如上文所述)。因而Node_A開始等join(選票),Node_B、Node_C都向Node_A發送join,當Node_A接收到一次join時,加上它本身的一票,就得到了兩票了(超過半數),因而Node_A成爲Master。此時cluster_state(集羣狀態)中包含兩個節點,當Node_A再收到另外一個節點的join時,cluster_state包含所有三個節點。
4 選舉怎麼保證不腦裂?
基本原則仍是多數派的策略,若是必須獲得多數派的承認才能成爲Master,那麼顯然不可能有兩個Master都獲得多數派的承認。
上述流程中,master候選人須要等待多數派節點進行join後才能真正成爲master,就是爲了保證這個master獲得了多數派的承認。可是我這裏想說的是,上述流程在絕大部份場景下沒問題,聽上去也很是合理,可是倒是有bug的。
由於上述流程並無限制在選舉過程當中,一個Node只能投一票,那麼什麼場景下會投兩票呢?好比Node_B投Node_A一票,可是Node_A遲遲不成爲Master,Node_B等不及了發起了下一輪選主,這時候發現集羣裏多了個Node_0,Node_0優先級比Node_A還高,那Node_B確定就改投Node_0了。假設Node_0和Node_A都處在等選票的環節,那顯然這時候Node_B其實發揮了兩票的做用,並且投給了不一樣的人。
那麼這種問題應該怎麼解決呢,好比raft算法中就引入了選舉週期(term)的概念,保證了每一個選舉週期中每一個成員只能投一票,若是須要再投就會進入下一個選舉週期,term+1。假如最後出現兩個節點都認爲本身是master,那麼確定有一個term要大於另外一個的term,並且由於兩個term都收集到了多數派的選票,因此多數節點的term是較大的那個,保證了term小的master不可能commit任何狀態變動(commit須要多數派節點先持久化日誌成功,因爲有term檢測,不可能達到多數派持久化條件)。這就保證了集羣的狀態變動老是一致的。
而ES目前(6.2版本)並無解決這個問題,構造相似場景的測試case能夠看到會選出兩個master,兩個node都認爲本身是master,向全集羣發佈狀態變動,這個發佈也是兩階段的,先保證多數派節點「接受」此次變動,而後再要求所有節點commit此次變動。很不幸,目前兩個master可能都完成第一個階段,進入commit階段,致使節點間狀態出現不一致,而在raft中這是不可能的。那麼爲何都能完成第一個階段呢,由於第一個階段ES只是將新的cluster_state作簡單的檢查後放入內存隊列,若是當前cluster_state的master爲空,不會對新的cluster_state中的master作檢查,即在接受了Node_A成爲master的cluster_state後(還未commit),還能夠繼續接受Node_B成爲cluster_state。這就使Node_A和Node_B都能達到commit條件,發起commit命令,從而將集羣狀態引向不一致。固然,這種腦裂很快會自動恢復,由於不一致發生後某個master再次發佈cluster_state時就會發現沒法達到多數派條件,或者是發現它的follower並不構成多數派而自動降級爲candidate等。
這裏要表達的是,ES的ZenDiscovery模塊與成熟的一致性方案相比,在某些特殊場景下存在缺陷,下面講ES的meta變動流程時也會分析其餘的ES沒法知足一致性的場景。
錯誤檢測
這裏的錯誤檢測能夠理解爲相似心跳的機制,有兩類錯誤檢測,一類是Master按期檢測集羣內其餘的Node,另外一類是集羣內其餘的Node按期檢測當前集羣的Master。檢查的方法就是按期執行ping請求。ES文檔:
There are two fault detection processes running. The first is by the master, to ping all the other nodes in the cluster and verify that they are alive. And on the other end, each node pings to master to verify if its still alive or an election process needs to be initiated.
若是Master檢測到某個Node連不上了,會執行removeNode的操做,將節點從cluster_state中移除,併發布新的cluster_state。當各個模塊apply新的cluster_state時,就會執行一些恢復操做,好比選擇新的primaryShard或者replica,執行數據複製等。
若是某個Node發現Master連不上了,會清空pending在內存中還未commit的new cluster_state,而後發起rejoin,從新加入集羣(若是達到選舉條件則觸發新master選舉)。
2. rejoin
除了上述兩種狀況,還有一種狀況是Master發現本身已經不知足多數派條件(>=minimumMasterNodes)了,須要主動退出master狀態(退出master狀態並執行rejoin)以免腦裂的發生,那麼master如何發現本身須要rejoin呢?
上面提到,當有節點連不上時,會執行removeNode。在執行removeNode時判斷剩餘的Node是否知足多數派條件,若是不知足,則執行rejoin。
if (electMasterService.hasEnoughMasterNodes(remainingNodesClusterState.nodes()) == false) { final int masterNodes = electMasterService.countMasterNodes(remainingNodesClusterState.nodes()); rejoin.accept(LoggerMessageFormat.format("not enough master nodes (has [{}], but needed [{}])", masterNodes, electMasterService.minimumMasterNodes())); return resultBuilder.build(currentState); } else { return resultBuilder.build(allocationService.deassociateDeadNodes(remainingNodesClusterState, true, describeTasks(tasks))); }
在publish新的cluster_state時,分爲send階段和commit階段,send階段要求多數派必須成功,而後再進行commit。若是在send階段沒有實現多數派返回成功,那麼多是有了新的master或者是沒法鏈接到多數派個節點等,則master須要執行rejoin。
try { publishClusterState.publish(clusterChangedEvent, electMaster.minimumMasterNodes(), ackListener); } catch (FailedToCommitClusterStateException t) { // cluster service logs a WARN message logger.debug("failed to publish cluster state version [{}](not enough nodes acknowledged, min master nodes [{}])", newState.version(), electMaster.minimumMasterNodes()); synchronized (stateMutex) { pendingStatesQueue.failAllStatesAndClear( new ElasticsearchException("failed to publish cluster state")); rejoin("zen-disco-failed-to-publish"); } throw t; }
在對其餘節點進行按期的ping時,發現有其餘節點也是master,此時會比較本節點與另外一個master節點的cluster_state的version,誰的version大誰成爲master,version小的執行rejoin。
if (otherClusterStateVersion > localClusterState.version()) { rejoin("zen-disco-discovered another master with a new cluster_state [" + otherMaster + "][" + reason + "]"); } else { // TODO: do this outside mutex logger.warn("discovered [{}] which is also master but with an older cluster_state, telling [{}] to rejoin the cluster ([{}])", otherMaster, otherMaster, reason); try { // make sure we're connected to this node (connect to node does nothing if we're already connected) // since the network connections are asymmetric, it may be that we received a state but have disconnected from the node // in the past (after a master failure, for example) transportService.connectToNode(otherMaster); transportService.sendRequest(otherMaster, DISCOVERY_REJOIN_ACTION_NAME, new RejoinClusterRequest(localClusterState.nodes().getLocalNodeId()), new EmptyTransportResponseHandler(ThreadPool.Names.SAME) { @Override public void handleException(TransportException exp) { logger.warn((Supplier<?>) () -> new ParameterizedMessage("failed to send rejoin request to [{}]", otherMaster), exp); } }); } catch (Exception e) { logger.warn((Supplier<?>) () -> new ParameterizedMessage("failed to send rejoin request to [{}]", otherMaster), e); } }
集羣擴縮容
上面講了節點發現、Master選舉、錯誤檢測等機制,那麼如今咱們能夠來看一下如何對集羣進行擴縮容。
1 擴容DataNode
假設一個ES集羣存儲或者計算資源不夠了,咱們須要進行擴容,這裏咱們只針對DataNode,即配置爲:
conf/elasticsearch.yml:
node.master: false node.data: true
而後須要配置集羣名、節點名等其餘配置,爲了讓該節點可以加入集羣,咱們把discovery.zen.ping.unicast.hosts配置爲集羣中的master-eligible node。
conf/elasticsearch.yml:
cluster.name: es-cluster node.name: node_Z discovery.zen.ping.unicast.hosts: ["x.x.x.x", "x.x.x.y", "x.x.x.z"]
而後啓動節點,節點會自動加入到集羣中,集羣會自動進行rebalance,或者經過reroute api進行手動操做。
https://www.elastic.co/guide/...
https://www.elastic.co/guide/...
2 縮容DataNode
假設一個ES集羣使用的機器數太多了,須要縮容,咱們怎麼安全的操做來保證數據安全,而且不影響可用性呢?
首先,咱們選擇須要縮容的節點,注意本節只針對DataNode的縮容,MasterNode縮容涉及到更復雜的問題,下面再講。
而後,咱們須要把這個Node上的Shards遷移到其餘節點上,方法是先設置allocation規則,禁止分配Shard到要縮容的機器上,而後讓集羣進行rebalance。
PUT _cluster/settings
{
"transient" : {
"cluster.routing.allocation.exclude._ip" : "10.0.0.1"
}
}
等這個節點上的數據所有遷移完成後,節點能夠安全下線。
更詳細的操做方式能夠參考官方文檔:
https://www.elastic.co/guide/...
3 擴容MasterNode
假如咱們想擴容一個MasterNode(master-eligible node), 那麼有個須要考慮的問題是,上面提到爲了不腦裂,ES是採用多數派的策略,須要配置一個quorum數:
conf/elasticsearch.yml:
discovery.zen.minimum_master_nodes: 2
假設以前3個master-eligible node,咱們能夠配置quorum爲2,若是擴容到4個master-eligible node,那麼quorum就要提升到3。
因此咱們應該先把discovery.zen.minimum_master_nodes這個配置改爲3,再擴容master,更改這個配置能夠經過API的方式:
curl -XPUT localhost:9200/_cluster/settings -d '{
"persistent" : { "discovery.zen.minimum_master_nodes" : 3 }
}'
這個API發送給當前集羣的master,而後新的值當即生效,而後master會把這個配置持久化到cluster meta中,以後全部節點都會以這個配置爲準。
可是這種方式有個問題在於,配置文件中配置的值和cluster meta中的值極可能出現不一致,不一致很容易致使一些奇怪的問題,好比說集羣重啓後,在恢復cluster meta前就須要進行master選舉,此時只可能拿配置中的值,拿不到cluster meta中的值,可是cluster meta恢復後,又須要以cluster meta中的值爲準,這中間確定存在一些正確性相關的邊界case。
總之,動master節點以及相關的配置必定要謹慎,master配置錯誤頗有可能致使腦裂甚至數據寫壞、數據丟失等場景。
4 縮容MasterNode
縮容MasterNode與擴容跟擴容是相反的流程,咱們須要先把節點縮下來,再把quorum數調下來,再也不詳細描述。
與Zookeeper、raft等實現方式的比較
本篇講了ES集羣中節點相關的幾大功能的實現方式:
節點發現
Master選舉
錯誤檢測
集羣擴縮容
試想下,若是咱們使用Zookeeper來實現這幾個功能,會帶來哪些變化?
Zookeeper介紹
咱們首先介紹一下Zookeeper,熟悉的同窗能夠略過。
Zookeeper分佈式服務框架是Apache Hadoop 的一個子項目,它主要是用來解決分佈式應用中常常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項的管理等。
簡單來講,Zookeeper就是用於管理分佈式系統中的節點、配置、狀態,並完成各個節點間進行配置和狀態的同步等。大量的分佈式系統依賴於Zookeeper或者是相似的組件。
Zookeeper經過目錄樹的形式來管理數據,每一個節點稱爲一個znode,每一個znode由3部分組成:
此爲狀態信息, 描述該znode的版本, 權限等信息.
與該znode關聯的數據.
該znode下的子節點.
stat中有一項是ephemeralOwner,若是有值,表明是一個臨時節點,臨時節點會在session結束後刪除,能夠用來輔助應用進行master選舉和錯誤檢測。
Zookeeper提供watch功能,能夠用於監聽相應的事件,好比某個znode下的子節點的增減,某個znode自己的增減,某個znode的更新等。
怎麼使用Zookeeper實現ES的上述功能
集羣擴縮容:擴縮容將再也不須要考慮minimum_master_nodes配置的問題,會變得更容易。
使用Zookeeper的好處是,把一些複雜的分佈式一致性問題交給Zookeeper來作,ES自己的邏輯就能夠簡化不少,正確性也有保證,這也是大部分分佈式系統實踐過的路子。而ES的這套ZenDiscovery機制經歷過不少次bug fix,到目前仍有一些邊角的場景存在bug,並且運維也不簡單。
那爲何ES不使用Zookeeper呢,大概是官方開發以爲增長Zookeeper依賴後會多依賴一個組件,使集羣部署變得更復雜,用戶在運維時須要多運維一個Zookeeper。
那麼在自主實現這條路上,還有什麼別的算法選擇嗎?固然有的,好比raft。
2. 與使用raft相比
raft算法是近幾年很火的一個分佈式一致性算法,其實現相比paxos簡單,在各類分佈式系統中也獲得了應用。這裏再也不描述其算法的細節,咱們單從master選舉算法角度,比較一下raft與ES目前選舉算法的異同點:
相同點
多數派原則:必須獲得超過半數的選票才能成爲master。
選出的leader必定擁有最新已提交數據:在raft中,數據更新的節點不會給數據舊的節點投選票,而當選須要多數派的選票,則當選人必定有最新已提交數據。在es中,version大的節點排序優先級高,一樣用於保證這一點。
不一樣點
正確性論證:raft是一個被論證過正確性的算法,而ES的算法是一個沒有通過論證的算法,只能在實踐中發現問題,作bug fix,這是我認爲最大的不一樣。
是否有選舉週期term:raft引入了選舉週期的概念,每輪選舉term加1,保證了在同一個term下每一個參與人只能投1票。ES在選舉時沒有term的概念,不能保證每輪每一個節點只投一票。
選舉的傾向性:raft中只要一個節點擁有最新的已提交的數據,則有機會選舉成爲master。在ES中,version相同時會按照NodeId排序,老是NodeId小的人優先級高。
raft從正確性上看確定是更好的選擇,而ES的選舉算法通過幾回bug fix也愈來愈像raft。固然,在ES最先開發時尚未raft,而將來ES若是繼續沿着這個方向走極可能最終就變成一個raft實現。
raft不只僅是選舉,下一篇介紹meta數據一致性時也會繼續比較ES目前的實現與raft的異同。
本篇介紹了Elasticsearch集羣的組成、節點發現、master選舉、故障檢測和擴縮容等方面的實現,與通常的文章不一樣,本文對其原理、存在的問題也進行了一些分析,並與其餘實現方式進行了比較。
做爲Elasticsearch分佈式一致性原理剖析系列的第一篇,本文先從節點入手,下一篇會介紹meta數據變動的一致性問題,會在本文的基礎上對ES的分佈式原理作進一步分析。
詳情請閱讀原文