摘要:前言分布式一致性原理剖析系列將會對的分布式一致性原理進行詳細的剖析,介紹其實現方式原理以及其存在的問題等基于版本。中需要持久化的包括當前版本號,每次更新加。收集不到足夠的,于是本次發布失敗,同時退出狀態。
前言
“Elasticsearch分布式一致性原理剖析”系列將會對Elasticsearch的分布式一致性原理進行詳細的剖析,介紹其實現方式、原理以及其存在的問題等(基于6.2版本)。前一篇的內容包括了ES的集群組成、節點發現與Master選舉、錯誤檢測與集群擴縮容等。本篇將在前一篇的基礎上,重點分析ES中meta更新的一致性問題,為了便于讀者理解 ,本文還介紹了Master管理集群的方式、meta組成、存儲方式等等。目錄如下:
Master如何管理集群
Meta組成、存儲和恢復
ClusterState的更新流程
如何解決當前的一致性問題
小結
Master如何管理集群在上一篇文章中,我們介紹了ES集群的組成,如何發現節點,選舉Master等。那么在選舉出Master之后,Master如何管理集群呢?比如以下問題:
Master如何處理新建或刪除Index?
Master如何對Shard進行重新調度,實現負載均衡?
既然要管理集群,那么Master節點必然需要以某種方式通知其他節點,從而讓其他節點執行相應的動作,來完成某些事情。比如建立一個新的Index就需要將其Shard分配在某些節點上,在這些節點上需要創建出對應Shard的目錄,并在內存中創建對應Shard的一些結構等。
在ES中,Master節點是通過發布ClusterState來通知其他節點的。Master會將新的ClusterState發布給其他的所有節點,當節點收到新的ClusterState后,會把新的ClusterState發給相關的各個模塊,各個模塊根據新的ClusterState判斷是否要做什么事情,比如創建Shard等。即這是一種通過Meta數據來驅動各個模塊工作的方式。
在Master進行Meta變更并通知所有節點的過程中,需要考慮Meta變更的一致性問題,假如這個過程中Master掛掉了,那么可能只有部分節點按照新的Meta執行了操作。當選舉出新的Master后,需要保證所有節點都要按照最新的Meta執行操作,不能回退,因為已經有節點按照新的Meta執行操作了,再回退就會導致不一致。
ES中只要新Meta在一個節點上被commit,那么就會開始執行相應的操作。因此我們要保證一旦新Meta在某個節點上被commit,此后無論誰是master,都要基于這個commit來產生更新的meta,否則就可能產生不一致。本文會分析ES處理這一問題的策略和存在的問題。
Meta的組成、存儲和恢復在介紹Meta更新流程前,我們先介紹一下ES中Meta的組成、存儲方式和恢復方式,不關心這部分內容的讀者可以略過本節。
1. Meta:ClusterState、MetaData、IndexMetaData
Meta是用來描述數據的數據。在ES中,Index的mapping結構、配置、持久化狀態等就屬于meta數據,集群的一些配置信息也屬于meta。這類meta數據非常重要,假如記錄某個index的meta數據丟失了,那么集群就認為這個index不再存在了。ES中的meta數據只能由master進行更新,master相當于是集群的大腦。
ClusterState
集群中的每個節點都會在內存中維護一個當前的ClusterState,表示當前集群的各種狀態。ClusterState中包含一個MetaData的結構,MetaData中存儲的內容更符合meta的特征,而且需要持久化的信息都在MetaData中,此外的一些變量可以認為是一些臨時狀態,是集群運行中動態構建出來的。
ClusterState內容包括: long version: 當前版本號,每次更新加1 String stateUUID:該state對應的唯一id RoutingTable routingTable:所有index的路由表 DiscoveryNodes nodes:當前集群節點 MetaData metaData:集群的meta數據 ClusterBlocks blocks:用于屏蔽某些操作 ImmutableOpenMapcustoms: 自定義配置 ClusterName clusterName:集群名
MetaData
上面提到,MetaData更符合meta的特征,而且需要持久化,那么我們看下這個MetaData中主要包含哪些東西:
MetaData中需要持久化的包括: String clusterUUID:集群的唯一id。 long version:當前版本號,每次更新加1 Settings persistentSettings:持久化的集群設置 ImmutableOpenMapindices: 所有Index的Meta ImmutableOpenMap templates:所有模版的Meta ImmutableOpenMap customs: 自定義配置
我們看到,MetaData主要是集群的一些配置,集群所有Index的Meta,所有Template的Meta。下面我們再分析一下IndexMetaData,后面還會講到,雖然IndexMetaData也是MetaData的一部分,但是存儲上卻是分開存儲的。
IndexMetaData
IndexMetaData指具體某個Index的Meta,比如這個Index的shard數,replica數,mappings等。
IndexMetaData中需要持久化的包括: long version:當前版本號,每次更新加1。 int routingNumShards: 用于routing的shard數, 只能是該Index的numberOfShards的倍數,用于split。 State state: Index的狀態, 是個enum,值是OPEN或CLOSE。 Settings settings:numbersOfShards,numbersOfRepilicas等配置。 ImmutableOpenMapmappings:Index的mapping ImmutableOpenMap customs:自定義配置。 ImmutableOpenMap aliases: 別名 long[] primaryTerms:primaryTerm在每次Shard切換Primary時加1,用于保序。 ImmutableOpenIntMap > inSyncAllocationIds:處于InSync狀態的AllocationId,用于保證數據一致性,下一篇文章會介紹。
2. Meta的存儲
首先,在啟動ES的一個節點時,會配置一個data目錄,例如下面這個目錄。該節點只有一個單shard的Index。
$tree . `-- nodes `-- 0 |-- _state | |-- global-1.st | `-- node-0.st |-- indices | `-- 2Scrm6nuQOOxUN2ewtrNJw | |-- 0 | | |-- _state | | | `-- state-0.st | | |-- index | | | |-- segments_1 | | | `-- write.lock | | `-- translog | | |-- translog-1.tlog | | `-- translog.ckp | `-- _state | `-- state-2.st `-- node.lock
我們看到,ES進程會把Meta和Data都寫入這個目錄中,其中目錄名為_state的代表該目錄存儲的是meta文件,根據文件層級的不同,共有3種meta的存儲:
nodes/0/_state/:
這層目錄在節點級別,該目錄下的global-1.st文件存儲的是上文介紹的MetaData中除去IndexMetaData的部分,即一些集群級別的配置和templates。node-0.st中存儲的是NodeId。
nodes/0/indices/2Scrm6nuQOOxUN2ewtrNJw/_state/:
這層目錄在index級別,2Scrm6nuQOOxUN2ewtrNJw是IndexId,該目錄下的state-2.st文件存儲的是上文介紹的IndexMetaData。
nodes/0/indices/2Scrm6nuQOOxUN2ewtrNJw/0/_state/:
這層目錄在shard級別,該目錄下的state-0.st存儲的是ShardStateMetaData,包含是否是primary和allocationId等信息。ShardStateMetaData是在IndexShard模塊中管理,與其他Meta關聯不大,本文不做過多介紹。
可以看到,集群相關的MetaData和Index的MetaData是在不同的目錄中存儲的。另外,集群相關的Meta會在所有的MasterNode和DataNode上存儲,而Index的Meta會在所有的MasterNode和存儲了該Index數據的DataNode上存儲。
這里有個問題是,MetaData是由Master管理的,為什么DataNode上也要保存MetaData呢?主要原因是考慮到數據的安全性,很多用戶沒有考慮Master節點的高可用和數據高可靠,在部署ES集群時只配置了一個MasterNode,如果這個節點不可用,就會出現Meta丟失,后果非常嚴重。
3. Meta的恢復
假設ES集群重啟了,那么所有進程都沒有了之前的Meta信息,需要有一個角色來恢復Meta,這個角色就是Master。所以ES集群需要先進行Master選舉,選出Master后,才會進行故障恢復。
當Master選舉出來后,Master進程還會等待一些條件,比如集群當前的節點數大于某個數目等,這是避免有些DataNode還沒有連上來,造成不必要的數據恢復等。
當Master進程決定進行恢復Meta時,它會向集群中的MasterNode和DataNode請求其機器上的MetaData。對于集群的Meta,選擇其中version最大的版本。對于每個Index的Meta,也選擇其中最大的版本。然后將集群的Meta和每個Index的Meta再組合起來,構成當前的最新Meta。
ClusterState的更新流程現在我們開始分析ClusterState的更新流程,并通過這個流程來看ES如何保證Meta更新的一致性。
1. master進程內不同線程更改ClusterState時的原子性保證
首先,master進程內不同線程更改ClusterState時要保證是原子的。試想一下這個場景,有兩個線程都在修改ClusterState,各自更改其中的一部分。假如沒有任何并發的保護,那么最后提交的線程可能就會覆蓋掉前一個線程的修改,或者產生不符合條件的狀態變更的發生。
ES解決這個問題的方式是,每次需要更新ClusterState時提交一個Task給MasterService,MasterService中只使用一個線程來串行處理這些Task,每次處理時把當前的ClusterState作為Task中execute函數的參數。即保證了所有的Task都是在currentClusterState的基礎上進行更改,然后不同的Task是串行執行的。
2. ClusterState更改如何保證一旦commit,后續就一定會在此基礎上commit,不會回退
這里是為了解決這樣一個問題,我們知道,新的Meta一旦在某個節點上commit,那么這個節點就會執行相應的操作,比如刪除某個Shard等,這樣的操作是不可回退的。而假如此時Master節點掛掉了,新產生的Master一定要在新的Meta上進行更改,不能出現回退,否則就會出現Meta回退了但是操作無法回退的情況。本質上就是Meta更新沒有保證一致性。
早期的ES版本沒有解決這個問題,后來引入了兩階段提交的方式(Add two phased commit to Cluster State publishing)。所謂的兩階段提交,是把Master發布ClusterState分成兩步,第一步是向所有節點send最新的ClusterState,當有超過半數的master節點返回ack時,再發送commit請求,要求節點commit接收到的ClusterState。如果沒有超過半數的節點返回ack,那么認為本次發布失敗,同時退出master狀態,執行rejoin重新加入集群。
兩階段提交可以解決部分一致性問題,比如以下這種場景:
NodeA本來是Master節點,但由于某些原因NodeB成了新的Master節點,而NodeA由于探測不及時還未發現。
NodeA認為自己仍然是Master,于是照常發布新的ClusterState。
由于此時NodeB是Master,說明超過半數的Master節點認為NodeB才是新的Master,于是超過半數的Master節點不會返回ack給NodeA。
NodeA收集不到足夠的ack,于是本次發布失敗,同時退出master狀態。
新的ClusterState不會在任何節點上commit,于是沒有不一致發生。
但是這種方式也存在很多一致性的問題,我們下一節來具體分析。
3. 一致性問題分析
ES中,Master發送commit的原則是只要有超過半數MasterNode(master-eligible node)接收了新的ClusterState就發送commit。那么實際上就是認為只要超過半數節點接收了新的ClusterState,這個ClusterState就一定可以被commit,不會在各種場景下回退。
問題1
第一階段master節點send新的ClusterState,接收到的節點只是把新的ClusterState放入內存一個隊列中,就會返回ack。這個過程沒有持久化,所以當master接收到超過半數的ack后,也不能認為這些節點上都有新的ClusterState了。
問題2
如果master在commit階段,只commit了少數幾個節點就出現了網絡分區,將master與這幾個少數節點分在了一起,其他節點可以互相訪問。此時其他節點構成多數派,會選舉出新的master,由于這部分節點中沒有任何節點commit了新的ClusterState,所以新的master仍會使用更新前的ClusterState,造成Meta不一致。
ES官方仍在追蹤這個bug:
https://www.elastic.co/guide/en/elasticsearch/resiliency/current/index.html Repeated network partitions can cause cluster state updates to be lost (STATUS: ONGOING) ...This problem is mostly fixed by #20384 (v5.0.0), which takes committed cluster state updates into account during master election. This considerably reduces the chance of this rare problem occurring but does not fully mitigate it. If the second partition happens concurrently with a cluster state update and blocks the cluster state commit message from reaching a majority of nodes, it may be that the in flight update will be lost. If the now-isolated master can still acknowledge the cluster state update to the client this will amount to the loss of an acknowledged change. Fixing that last scenario needs considerable work. We are currently working on it but have no ETA yet.
什么情況下會有問題
在兩階段提交中,很重要的一個條件是,“超過半數節點返回ack,表示接收了這個ClusterState”,這個條件并不能帶來任何保證。一方面接收ClusterState并不會持久化,另一方面接收了ClusterState也不會對未來選舉新Master產生任何干擾,因為選舉時只考慮已經commit的ClusterState。
在兩階段過程中,只到Master在超過半數MasterNode(master-eligible node)上commit了新的ClusterState,并且這些節點都完成了新ClusterState的持久化時,才到達一個安全的狀態。在開始commit到達到這個狀態之間,如果Master發送故障,就可能導致Meta發生不一致。
如何解決當前的一致性問題既然ES目前Meta更新存在一些一致性問題,那么我們來腦洞一下,如何解決這些一致性問題呢?
1. 實現一個標準的一致性算法,比如raft
第一種方式是實現一個標準的一致性算法,比如raft。在上一篇中,我們也比較了ES的選舉算法與raft算法的異同,下面我們繼續比較一下ES的meta更新流程與raft的日志復制流程。
相同點:
都是在得到超過半數節點應答之后,執行commit。
不同點:
raft算法中,follower接收到日志后就會進行持久化,寫到磁盤上。ES中,節點接收到ClusterState只是放到內存中的一個隊列中即返回,并不持久化。
raft算法可以保證在超過半數節點應答之后,這條日志一定可以被commit,而ES中沒有保證這一點,目前還存在一致性問題。
通過上面的比較,我們再次看到,ES中meta更新的算法與raft相比很相似,raft使用了更多的機制來保證一致性,而ES還存在一些問題。用ES官方的話來說,fix這些問題還需要大量的工作(considerable work)。
2. 借助額外的組件保證meta一致性
比如使用Zookeeper來保存Meta,用Zookeeper來保證Meta的一致性。這樣可以解決一致性的問題,但是性能的問題還需要再評估一下,比如Meta是否會過大而導致不保存在Zookeeper中,每次請求全量Meta還是Diff等。
3. 使用共享存儲來保存Meta
首先保證不會出現腦裂,然后可以使用共享存儲來保存Meta,解決Meta一致性的問題。這種方式會引入一個共享存儲,這個存儲系統需要具備高可靠、高可用特征。
作為Elasticsearch分布式一致性原理系列的第二篇,本文主要介紹了ES集群中Master節點發布Meta更新的流程,分析了其中的一致性問題。此外還介紹了Meta數據的組成和存儲方式等。下一篇文章會分析ES中如何保證數據的一致性,介紹其寫入流程和算法模型等。
詳情請閱讀原文
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/17712.html
摘要:前言分布式一致性原理剖析系列將會對的分布式一致性原理進行詳細的剖析,介紹其實現方式原理以及其存在的問題等基于版本。中需要持久化的包括當前版本號,每次更新加。收集不到足夠的,于是本次發布失敗,同時退出狀態。 前言Elasticsearch分布式一致性原理剖析系列將會對Elasticsearch的分布式一致性原理進行詳細的剖析,介紹其實現方式、原理以及其存在的問題等(基于6.2版本)。前一...
摘要:前言分布式一致性原理剖析系列將會對的分布式一致性原理進行詳細的剖析,介紹其實現方式原理以及其存在的問題等基于版本。中需要持久化的包括當前版本號,每次更新加。收集不到足夠的,于是本次發布失敗,同時退出狀態。 前言Elasticsearch分布式一致性原理剖析系列將會對Elasticsearch的分布式一致性原理進行詳細的剖析,介紹其實現方式、原理以及其存在的問題等(基于6.2版本)。前一...
閱讀 853·2021-11-24 09:38
閱讀 1085·2021-10-08 10:05
閱讀 2577·2021-09-10 11:21
閱讀 2800·2019-08-30 15:53
閱讀 1827·2019-08-30 15:52
閱讀 1964·2019-08-29 12:17
閱讀 3418·2019-08-29 11:21
閱讀 1609·2019-08-26 12:17