ZooKeeper学习第七期--ZooKeeper一致性原理
ZooKeeper學(xué)習(xí)第六期---ZooKeeper機(jī)制架構(gòu)
ZooKeeper學(xué)習(xí)第一期---Zookeeper簡單介紹
ZooKeeper學(xué)習(xí)第二期--ZooKeeper安裝配置?
ZooKeeper學(xué)習(xí)第三期---Zookeeper命令操作
ZooKeeper學(xué)習(xí)第四期---構(gòu)建ZooKeeper應(yīng)用
ZooKeeper學(xué)習(xí)第五期--ZooKeeper管理分布式環(huán)境中的數(shù)據(jù)
ZooKeeper學(xué)習(xí)第六期---ZooKeeper機(jī)制架構(gòu)
ZooKeeper學(xué)習(xí)第七期--ZooKeeper一致性原理
ZooKeeper學(xué)習(xí)第八期——ZooKeeper伸縮性
?
一、ZooKeeper 的實(shí)現(xiàn)
1.1 ZooKeeper處理單點(diǎn)故障
我們知道可以通過ZooKeeper對分布式系統(tǒng)進(jìn)行Master選舉,來解決分布式系統(tǒng)的單點(diǎn)故障,如圖所示。
那么我們繼續(xù)分析一下,ZooKeeper通過Master選舉來幫助分布式系統(tǒng)解決單點(diǎn)故障, 保證該系統(tǒng)中每時每刻只有一個Master為分布式系統(tǒng)提供服務(wù)。也就是說分布式的單點(diǎn)問題交給了ZooKeeper來處理,不知道大家此時有沒有發(fā)現(xiàn)一 個問題——"故障轉(zhuǎn)移到了ZooKeeper身上"。大家看一下圖就會發(fā)現(xiàn),如果我們的ZooKeeper只用一臺機(jī)器來提供服務(wù),若這臺機(jī)器掛了,那么 該分布式系統(tǒng)就直接變成雙Master模式了,那么我們在分布式系統(tǒng)中引入ZooKeeper也就失去了意義。那么這也就意味著,ZooKeeper在其實(shí)現(xiàn)的過程中要做一些可用性和恢復(fù)性的保證。這樣才能讓我們放心的以ZooKeeper為起點(diǎn)來構(gòu)建我們的分布式系統(tǒng),來達(dá)到節(jié)省成本和減少bug的目的。
1.2 ZooKeeper運(yùn)行模式
ZooKeeper服務(wù)有兩種不同的運(yùn)行模式。一種是"獨(dú)立模式"(standalone mode),即只有一個ZooKeeper服務(wù)器。這種模式較為簡單,比較適合于測試環(huán)境,甚至可以在單元測試中采用,但是不能保證高可用性和恢復(fù)性。在生產(chǎn)環(huán)境中的ZooKeeper通常以"復(fù)制模式"(replicated mode)運(yùn)行于一個計算機(jī)集群上,這個計算機(jī)集群被稱為一個"集合體"(ensemble)。
?
ZooKeeper通過復(fù)制來實(shí)現(xiàn)高可用性,只要集合體中半數(shù)以上的機(jī)器處于可用狀態(tài),它就能夠提供服務(wù)。例如,在一個有5個節(jié)點(diǎn)的集合體中,每個Follower節(jié)點(diǎn)的數(shù)據(jù)都是Leader節(jié)點(diǎn)數(shù)據(jù)的副本,也就是說我們的每個節(jié)點(diǎn)的數(shù)據(jù)視圖都是一樣的,這樣就可以有五個節(jié)點(diǎn)提供ZooKeeper服務(wù)。并且集合體中任意2臺機(jī)器出現(xiàn)故障,都可以保證服務(wù)繼續(xù),因?yàn)槭O碌?臺機(jī)器超過了半數(shù)。
注意,6個節(jié)點(diǎn)的集合體也只能夠容忍2臺機(jī)器出現(xiàn)故障,因?yàn)槿绻?臺機(jī)器出現(xiàn)故障,剩下的3臺機(jī)器沒有超過集合體的半數(shù)。出于這個原因,一個集合體通常包含奇數(shù)臺機(jī)器。
從概念上來說,ZooKeeper它所做的就是確保對Znode樹的每一個修改都會被復(fù)制到集合體中超過半數(shù)的 機(jī)器上。如果少于半數(shù)的機(jī)器出現(xiàn)故障,則最少有一臺機(jī)器會保存最新的狀態(tài),那么這臺機(jī)器就是我們的Leader。其余的副本最終也會更新到這個狀態(tài)。如果 Leader掛了,由于其他機(jī)器保存了Leader的副本,那就可以從中選出一臺機(jī)器作為新的Leader繼續(xù)提供服務(wù)。
1.3 ZooKeeper的讀寫機(jī)制
(1) 概述
ZooKeeper的核心思想是,提供一個非鎖機(jī)制的Wait Free的用于分布式系統(tǒng)同步的核心服務(wù)。提供簡單的文件創(chuàng)建、讀寫操作接口,其系統(tǒng)核心本身對文件讀寫并不提供加鎖互斥的服務(wù),但是提供基于版本比對的更新操作,客戶端可以基于此自己實(shí)現(xiàn)加鎖邏輯。如下圖1.3所示。
?
(2) ZK集群服務(wù)
?Zookeeper是一個由多個Server組成的集群,該集群有一個Leader,多個Follower。客戶端可以連接任意ZooKeeper服務(wù)節(jié)點(diǎn)來讀寫數(shù)據(jù),如下圖1.4所示。
?
ZK集群中每個Server,都保存一份數(shù)據(jù)副本。Zookeeper使用簡單的同步策略,通過以下兩條基本保證來實(shí)現(xiàn)數(shù)據(jù)的一致性:
① 全局串行化所有的寫操作
② 保證同一客戶端的指令被FIFO執(zhí)行(以及消息通知的FIFO)
所有的讀請求由Zk Server 本地響應(yīng),所有的更新請求將轉(zhuǎn)發(fā)給Leader,由Leader實(shí)施。
(3) ZK組件
ZK組件,如圖1.5所示。ZK組件除了請求處理器(Request Processor)以外,組成ZK服務(wù)的每一個Server會復(fù)制這些組件的副本。?
?
ReplicatedDatabase是一個內(nèi)存數(shù)據(jù)庫,它包含了整個Data Tree。為了恢復(fù),更新會被記錄到磁盤,并且寫在被應(yīng)用到內(nèi)存數(shù)據(jù)庫之前,先被序列化到磁盤。
每一個ZK Server,可服務(wù)于多個Client。Client可以連接到一臺Server,來提交請求。讀請求,由每臺Server數(shù)據(jù)庫的本地副本來進(jìn)行服務(wù)。改變服務(wù)器的狀態(tài)的寫請求,需要通過一致性協(xié)議來處理。
作為一致性協(xié)議的一部分,來自Client的所有寫請求,都要被轉(zhuǎn)發(fā)到一個單獨(dú)的Server,稱作Leader。ZK集群中其他Server 稱作Follower,負(fù)責(zé)接收Leader發(fā)來的提議消息,并且對消息轉(zhuǎn)發(fā)達(dá)成一致。消息層處理leader失效,同步Followers和Leader。
ZooKeeper使用自定義的原子性消息協(xié)議。由于消息傳送層是原子性的,ZooKeeper能夠保證本地副本不產(chǎn)生分歧。當(dāng)leader收到一個寫請求,它會計算出當(dāng)寫操作完成后系統(tǒng)將會是什么狀態(tài),接著將之轉(zhuǎn)變?yōu)橐粋€捕獲狀態(tài)的事務(wù)。
(4) ZK性能
ZooKeeper被應(yīng)用程序廣泛使用,并有數(shù)以千計 的客戶端同時的訪問它,所以我們需要高吞吐量。我們?yōu)閆ooKeeper 設(shè)計的工作負(fù)載的讀寫比例是 2:1以上。然而我們發(fā)現(xiàn),ZooKeeper的高寫入吞吐量,也允許它被用于一些寫占主導(dǎo)的工作負(fù)載。ZooKeeper通過每臺Server上的本地 ZK的狀態(tài)副本,來提供高讀取吞吐量。因此,容錯性和讀吞吐量是以添加到該服務(wù)的服務(wù)器數(shù)量為尺度。寫吞吐量并不以添加到該服務(wù)的機(jī)器數(shù)量為尺度。
例如,在它的誕生地Yahoo公司,對于寫占主導(dǎo)的工作負(fù)載來說,ZooKeeper的基準(zhǔn)吞吐量已經(jīng)超過每秒10000個操作;對于常規(guī)的以讀為主導(dǎo)的工作負(fù)載來說,吞吐量更是高出了好幾倍。
二、ZooKeeper的保證
經(jīng)過上面的分析,我們知道要保證ZooKeeper服務(wù)的高可用性就需要采用分布式模式,來冗余數(shù)據(jù)寫多份,寫多份帶來一致性問題,一致性問題又會帶來性能問題,那么就此陷入了無解的死循環(huán)。那么在這,就涉及到了我們分布式領(lǐng)域的著名的CAP理論,在這就簡單的給大家介紹一下,關(guān)于CAP的詳細(xì)內(nèi)容大家可以網(wǎng)上查閱。
2.1 CAP理論
(1) 理論概述
分布式領(lǐng)域中存在CAP理論:
①?C:Consistency,一致性,數(shù)據(jù)一致更新,所有數(shù)據(jù)變動都是同步的。
②?A:Availability,可用性,系統(tǒng)具有好的響應(yīng)性能。
③?P:Partition tolerance,分區(qū)容錯性。以實(shí)際效果而言,分區(qū)相當(dāng)于對通信的時限要求。系統(tǒng)如果不能在時限內(nèi)達(dá)成數(shù)據(jù)一致性,就意味著發(fā)生了分區(qū)的情況,必須就當(dāng)前操作在C和A之間做出選擇,也就是說無論任何消息丟失,系統(tǒng)都可用。
該理論已被證明:任何分布式系統(tǒng)只可同時滿足兩點(diǎn),無法三者兼顧。 因此,將精力浪費(fèi)在思考如何設(shè)計能滿足三者的完美系統(tǒng)上是愚鈍的,應(yīng)該根據(jù)應(yīng)用場景進(jìn)行適當(dāng)取舍。
(2)?一致性分類
一致性是指從系統(tǒng)外部讀取系統(tǒng)內(nèi)部的數(shù)據(jù)時,在一定約束條件下相同,即數(shù)據(jù)變動在系統(tǒng)內(nèi)部各節(jié)點(diǎn)應(yīng)該是同步的。根據(jù)一致性的強(qiáng)弱程度不同,可以將一致性級別分為如下幾種:
① 強(qiáng)一致性(strong consistency)。任何時刻,任何用戶都能讀取到最近一次成功更新的數(shù)據(jù)。
② 單調(diào)一致性(monotonic consistency)。任何時刻,任何用戶一旦讀到某個數(shù)據(jù)在某次更新后的值,那么就不會再讀到比這個值更舊的值。也就是說,可獲取的數(shù)據(jù)順序必是單調(diào)遞增的。
③ 會話一致性(session consistency)。任何用戶在某次會話中,一旦讀到某個數(shù)據(jù)在某次更新后的值,那么在本次會話中就不會再讀到比這個值更舊的值。會話一致性是在單調(diào)一致性的基礎(chǔ)上進(jìn)一步放松約束,只保證單個用戶單個會話內(nèi)的單調(diào)性,在不同用戶或同一用戶不同會話間則沒有保障。
④?最終一致性(eventual consistency)。用戶只能讀到某次更新后的值,但系統(tǒng)保證數(shù)據(jù)將最終達(dá)到完全一致的狀態(tài),只是所需時間不能保障。
⑤ 弱一致性(weak consistency)。用戶無法在確定時間內(nèi)讀到最新更新的值。
2.2 ZooKeeper與CAP理論
我們知道ZooKeeper也是一種分布式系統(tǒng),它在一致性上有人認(rèn)為它提供的是一種強(qiáng)一致性的服務(wù)(通過sync操作),也有人認(rèn)為是單調(diào)一致性(更新時的大多說概念),還有人為是最終一致性(順序一致性),反正各有各的道理這里就不在爭辯了。然后它在分區(qū)容錯性和可用性上做了一定折中,這和CAP理論是吻合的。ZooKeeper從以下幾點(diǎn)保證了數(shù)據(jù)的一致性
① 順序一致性
來自任意特定客戶端的更新都會按其發(fā)送順序被提交。也就是說,如果一個客戶端將Znode z的值更新為a,在之后的操作中,它又將z的值更新為b,則沒有客戶端能夠在看到z的值是b之后再看到值a(如果沒有其他對z的更新)。
② 原子性
每個更新要么成功,要么失敗。這意味著如果一個更新失敗,則不會有客戶端會看到這個更新的結(jié)果。
③ 單一系統(tǒng)映像
一 個客戶端無論連接到哪一臺服務(wù)器,它看到的都是同樣的系統(tǒng)視圖。這意味著,如果一個客戶端在同一個會話中連接到一臺新的服務(wù)器,它所看到的系統(tǒng)狀態(tài)不會比 在之前服務(wù)器上所看到的更老。當(dāng)一臺服務(wù)器出現(xiàn)故障,導(dǎo)致它的一個客戶端需要嘗試連接集合體中其他的服務(wù)器時,所有滯后于故障服務(wù)器的服務(wù)器都不會接受該 連接請求,除非這些服務(wù)器趕上故障服務(wù)器。
④ 持久性
一個更新一旦成功,其結(jié)果就會持久存在并且不會被撤銷。這表明更新不會受到服務(wù)器故障的影響。
?
三、ZooKeeper原理
3.1 原理概述
Zookeeper的核心是原子廣播機(jī)制,這個機(jī)制保證了各個server之間的同步。實(shí)現(xiàn)這個機(jī)制的協(xié)議叫做Zab協(xié)議。Zab協(xié)議有兩種模式,它們分別是恢復(fù)模式和廣播模式。
(1) 恢復(fù)模式
當(dāng)服務(wù)啟動或者在領(lǐng)導(dǎo)者崩潰后,Zab就進(jìn)入了恢復(fù)模式,當(dāng)領(lǐng)導(dǎo)者被選舉出來,且大多數(shù)server完成了和leader的狀態(tài)同步以后,恢復(fù)模式就結(jié)束了。狀態(tài)同步保證了leader和server具有相同的系統(tǒng)狀態(tài)。
(2) 廣播模式
一旦Leader已經(jīng)和多數(shù)的Follower進(jìn)行了狀態(tài)同步后,他就可以開始廣播消息了,即進(jìn)入廣播狀態(tài)。這時候當(dāng)一個Server加入ZooKeeper服務(wù)中,它會在恢復(fù)模式下啟動,發(fā)現(xiàn)Leader,并和Leader進(jìn)行狀態(tài)同步。待到同步結(jié)束,它也參與消息廣播。ZooKeeper服務(wù)一直維持在Broadcast狀態(tài),直到Leader崩潰了或者Leader失去了大部分的Followers支持。
Broadcast模式極其類似于分布式事務(wù)中的2pc(two-phrase commit?兩階段提交):即Leader提起一個決議,由Followers進(jìn)行投票,Leader對投票結(jié)果進(jìn)行計算決定是否通過該決議,如果通過執(zhí)行該決議(事務(wù)),否則什么也不做。
在廣播模式ZooKeeper Server會接受Client請求,所有的寫請求都被轉(zhuǎn)發(fā)給領(lǐng)導(dǎo)者,再由領(lǐng)導(dǎo)者將更新廣播給跟隨者。當(dāng)半數(shù)以上的跟隨者已經(jīng)將修改持久化之后,領(lǐng)導(dǎo)者才會提交這個更新,然后客戶端才會收到一個更新成功的響應(yīng)。這個用來達(dá)成共識的協(xié)議被設(shè)計成具有原子性,因此每個修改要么成功要么失敗。
?
3.2 Zab協(xié)議詳解
3.2.1 廣播模式
廣播模式類似一個簡單的兩階段提交:Leader發(fā)起一個請求,收集選票,并且最終提交,圖3.3演示了我們協(xié)議的消息流程。我們可以簡化該兩階段提交協(xié)議,因?yàn)槲覀儾]有"aborts"的情況。followers要么確認(rèn)Leader的Propose,要么丟棄該Leader的Propose。沒有"aborts"意味著,只要有指定數(shù)量的機(jī)器確認(rèn)了該P(yáng)ropose,而不是等待所有機(jī)器的回應(yīng)。
?
廣播協(xié)議在所有的通訊過程中使用TCP的FIFO信道,通過使用該信道,使保持有序性變得非常的容易。通過FIFO信道,消息被有序的deliver。只要收到的消息一被處理,其順序就會被保存下來。
Leader會廣播已經(jīng)被deliver的Proposal消息。在發(fā)出一個Proposal消息前,Leader會分配給Proposal一個單調(diào)遞增的唯一id,稱之為zxid。因?yàn)閆ab保證了因果有序, 所以遞交的消息也會按照zxid進(jìn)行排序。廣播是把Proposal封裝到消息當(dāng)中,并添加到指向Follower的輸出隊(duì)列中,通過FIFO信道發(fā)送到 Follower。當(dāng)Follower收到一個Proposal時,會將其寫入到磁盤,可以的話進(jìn)行批量寫入。一旦被寫入到磁盤媒介當(dāng) 中,Follower就會發(fā)送一個ACK給Leader。 當(dāng)Leader收到了指定數(shù)量的ACK時,Leader將廣播commit消息并在本地deliver該消息。當(dāng)收到Leader發(fā)來commit消息 時,Follower也會遞交該消息。
需要注意的是, 該簡化的兩階段提交自身并不能解決Leader故障,所以我們 添加恢復(fù)模式來解決Leader故障。
3.2.2 恢復(fù)模式
(1) 恢復(fù)階段概述
正常工作時Zab協(xié)議會一直處于廣播模式,直到Leader故障或失去了指定數(shù)量的Followers。 為了保證進(jìn)度,恢復(fù)過程中必須選舉出一個新Leader,并且最終讓所有的Server擁有一個正確的狀態(tài)。對于Leader選舉,需要一個能夠成功高幾 率的保證存活的算法。Leader選舉協(xié)議,不僅能夠讓一個Leader得知它是leader,并且有指定數(shù)量的Follower同意該決定。如果 Leader選舉階段發(fā)生錯誤,那么Servers將不會取得進(jìn)展。最終會發(fā)生超時,重新進(jìn)行Leader選舉。在我們的實(shí)現(xiàn)中,Leader選舉有兩種不同的實(shí)現(xiàn)方式。如果有指定數(shù)量的Server正常運(yùn)行,快速選舉的完成只需要幾百毫秒。
(2)恢復(fù)階段的保證
該恢復(fù)過程的復(fù)雜部分是在一個給定的時間內(nèi),提議沖突的絕對數(shù)量。最大數(shù)量沖突提議是一個可配置的選項(xiàng),但是默認(rèn)是1000。為了使該協(xié)議能夠即使在Leader故障的情況下也能正常運(yùn)作。我們需要做出兩條具體的保證:
①?我們絕不能遺忘已經(jīng)被deliver的消息,若一條消息在一臺機(jī)器上被deliver,那么該消息必須將在每臺機(jī)器上deliver。
②?我們必須丟棄已經(jīng)被skip的消息。
(3) 保證示例
第一條:
若一條消息在一臺機(jī)器上被deliver,那么該消息必須將在每臺機(jī)器上deliver,即使那臺機(jī)器故障了。例如,出現(xiàn)了這樣一種情況:Leader發(fā)送了commit消息,但在該commit消息到達(dá)其他任何機(jī)器之前,Leader發(fā)生了故障。也就是說,只有Leader自己收到了commit消息。如圖3.4中的C2。
?
圖3.4是"第一條保證"(deliver消息不能忘記)的一個示例。在該圖中Server1是一個Leader,我們用L1表示,Server2和Server3為Follower。首先Leader發(fā)起了兩個Proposal,P1和P2,并將P1、P2發(fā)送給了Server1和Server2。然后Leader對P1發(fā)起了Commit即C1,之后又發(fā)起了一個Proposal即P3,再后來又對P2發(fā)起了commit即C2,就在此時我們的Leader掛了。那么這時候,P3和C2這兩個消息只有Leader自己收到了。
因?yàn)長eader已經(jīng)deliver了該C2消息,client能夠在消息中看到該事務(wù)的結(jié)果。所以該事務(wù)必須能夠在其他所有的Server中deliver,最終使得client看到了一個一致性的服務(wù)視圖。
第二條:
一個被skip的消息,必須仍然需要被skip。例如,發(fā)生了這樣一種情況:Leader發(fā)送了propose消息,但在該propose消息到達(dá)其他任何機(jī)器之前,Leader發(fā)生了故障。也就是說,只有Leader自己收到了propose消息。如圖3.4中的P3所示。
在圖3.4中沒有任何一個server能夠看到3號提議,所以在圖3.5中當(dāng)server 1恢復(fù)時他需要在系統(tǒng)恢復(fù)時丟棄三號提議P3。
?
在圖3.5是"第二條保證"(skip消息必須被丟棄)的一個示例。Server1掛掉以后,Server3被選舉為Leader,我們用L2表示。L2中還有未被deliver的消息P1、P2,所以,L2在發(fā)出新提議P10000001、P10000002之前,L2先將P1、P2兩個消息deliver。因此,L2先發(fā)出了兩個commit消息C1、C2,之后L2才發(fā)出了新的提議P10000001和P10000002。
如果Server1 恢復(fù)之后再次成為了Leader,此時再次將P3在P10000001和P10000002之后deliver,那么將違背順序性的保障。
(4) 保證的實(shí)現(xiàn)
如果Leader選舉協(xié)議保證了新Leader在Quorum Server中具有最高的提議編號,即Zxid最高。那么新選舉出來的leader將具有所有已deliver的消息。新選舉出來的Leader,在提出一個新消息之前,首先要保證事務(wù)日志中的所有消息都由Quorum Follower已Propose并deliver。需要注意的是,我們可以讓新Leader成為一個用最高zxid來處理事務(wù)的server,來作為一個優(yōu)化。這樣,作為新被選舉出來的Leader,就不必去從一組Followers中找出包含最高zxid的Followers和獲取丟失的事務(wù)。
① 第一條
所有的正確啟動的Servers,將會成為Leader或者跟隨一個Leader。Leader能夠確保它的Followers看到所有的提議,并deliver所有已經(jīng)deliver的消息。通過將新連接上的Follower所沒有見過的所有PROPOSAL進(jìn)行排隊(duì),并之后對該P(yáng)roposals的COMMIT消息進(jìn)行排隊(duì),直到最后一個COMMIT消息。在所有這樣的消息已經(jīng)排好隊(duì)之后,Leader將會把Follower加入到廣播列表,以便今后的提議和確認(rèn)。這一條是為了保證一致性,因?yàn)槿绻粭l消息P已經(jīng)在舊Leader-Server1中deliver了,即使它剛剛將消息P?deliver之后就掛了,但是當(dāng)舊Leader-Server1重啟恢復(fù)之后,我們的Client就可以從該Server中看到該消息P?deliver的事務(wù),所以為了保證每一個client都能看到一個一致性的視圖,我們需要將該消息在每個Server上deliver。
② 第二條
skip已經(jīng)Propose,但不能deliver的消息,處理起來也比較簡單。在我們的實(shí)現(xiàn)中,Zxid是由64位數(shù)字組成的,低32位用作簡單計數(shù)器。高32位是一個epoch。每當(dāng)新Leader接管它時,將獲取日志中Zxid最大的epoch,新Leader?Zxid的epoch位設(shè)置為epoch+1,counter位設(shè)置0。用epoch來標(biāo)記領(lǐng)導(dǎo)關(guān)系的改變,并要求Quorum Servers?通過epoch來識別該leader,避免了多個Leader用同一個Zxid發(fā)布不同的提議。
這 個方案的一個優(yōu)點(diǎn)就是,我們可以skip一個失敗的領(lǐng)導(dǎo)者的實(shí)例,從而加速并簡化了恢復(fù)過程。如果一臺宕機(jī)的Server重啟,并帶有未發(fā)布的 Proposal,那么先前的未發(fā)布的所有提議將永不會被deliver。并且它不能夠成為一個新leader,因?yàn)槿魏我环N可能的 Quorum Servers ,都會有一個Server其Proposal 來自與一個新epoch因此它具有一個較高的zxid。當(dāng)Server以Follower的身份連接,領(lǐng)導(dǎo)者檢查自身最后提交的提議,該提議的epoch 為Follower的最新提議的epoch(也就是圖3.5中新Leader-Server2中deliver的C2提議),并告訴Follower截斷 事務(wù)日志直到該epoch在新Leader中deliver的最后的Proposal即C2。在圖3.5中,當(dāng)舊Leader-Server1連接到了新leader-Server2,leader將告訴他從事務(wù)日志中清除3號提議P3,具體點(diǎn)就是清除P2之后的所有提議,因?yàn)镻2之后的所有提議只有舊Leader-Server1知道,其他Server不知道。
(5) Paxos與Zab
① Paxos一致性
Paxos的一致性不能達(dá)到ZooKeeper的要求,我們可以下面一個例子。我們假設(shè)ZK集群由三臺機(jī)器組成,Server1、Server2、Server3。Server1為Leader,他生成了 三條Proposal,P1、P2、P3。但是在發(fā)送完P(guān)1之后,Server1就掛了。如下圖3.6所示。
?
Server1掛掉之后,Server3被選舉成為Leader,因?yàn)樵赟erver3里只有一條Proposal—P1。所以,Server3在P1的基礎(chǔ)之上又發(fā)出了一條新Proposal—P2',P2'的Zxid為02。如下圖3.7所示。
Server2發(fā)送完P(guān)2'之后,它也掛了。此時Server1已經(jīng)重啟恢復(fù),并再次成為了Leader。那么,Server1將發(fā)送還沒有被deliver的Proposal—P2和P3。由于Follower-Server2中P2'的Zxid為02和Leader-Server1中P2的Zxid相等,所以P2會被拒絕。而P3,將會被Server2接受。如圖3.8所示。
?
我們分析一下Follower-Server2中的Proposal,由于P2'將P2的內(nèi)容覆蓋了。所以導(dǎo)致,Server2中的Proposal-P3無法生效,因?yàn)樗母腹?jié)點(diǎn)并不存在。
② Zab一致性
首先來分析一下,上面的示例中為什么不滿足ZooKeeper需求。ZooKeeper是一個樹形結(jié)構(gòu),很多操作都要先檢查才能確定能不能執(zhí)行,比如,在圖3.8中Server2有三條Proposal。P1的事務(wù)是創(chuàng)建節(jié)點(diǎn)"/zk",P2'是創(chuàng)建節(jié)點(diǎn)"/c",而P3是創(chuàng)建節(jié)點(diǎn)"/a/b",由于"/a"還沒建,創(chuàng)建"a/b"就搞不定了。那么,我們就能從此看出Paxos的一致性達(dá)不到ZooKeeper一致性的要求。
為了達(dá)到ZooKeeper所需要的一致性,ZooKeeper采用了Zab協(xié)議。Zab做了如下幾條保證,來達(dá)到ZooKeeper要求的一致性。
(a) Zab要保證同一個leader的發(fā)起的事務(wù)要按順序被apply,同時還要保證只有先前的leader的所有事務(wù)都被apply之后,新選的leader才能在發(fā)起事務(wù)。
(b) 一些已經(jīng)Skip的消息,需要仍然被Skip。
我想對于第一條保證大家都能理解,它主要是為了保證每 個Server的數(shù)據(jù)視圖的一致性。我重點(diǎn)解釋一下第二條,它是如何實(shí)現(xiàn)。為了能夠?qū)崿F(xiàn),Skip已經(jīng)被skip的消息。我們在Zxid中引入了 epoch,如下圖所示。每當(dāng)Leader發(fā)生變換時,epoch位就加1,counter位置0。
?
我們繼續(xù)使用上面的例子,看一下他是如何實(shí)現(xiàn)Zab的 第二條保證的。我們假設(shè)ZK集群由三臺機(jī)器組成,Server1、Server2、Server3。Server1為Leader,他生成了三條 Proposal,P1、P2、P3。但是在發(fā)送完P(guān)1之后,Server1就掛了。如下圖3.10所示。
?
Server1掛掉之后,Server3被選舉成為 Leader,因?yàn)樵赟erver3里只有一條Proposal—P1。所以,Server3在P1的基礎(chǔ)之上又發(fā)出了一條新Proposal—P2', 由于Leader發(fā)生了變換,epoch要加1,所以epoch由原來的0變成了1,而counter要置0。那么,P2'的Zxid為10。如下圖3.11所示。
?
?
?Server2發(fā)送完P(guān)2'之后,它也掛了。此時Server1已經(jīng)重啟恢復(fù),并再次成為了Leader。那么,Server1將發(fā)送還沒有被deliver的Proposal—P2和P3。由于Server2中P2'的Zxid為10,而Leader-Server1中P2和P3的Zxid分別為02和03,P2'的epoch位高于P2和P3。所以此時Leader-Server1的P2和P3都會被拒絕,那么我們Zab的第二條保證也就實(shí)現(xiàn)了。如圖3.12所示。
?
總結(jié)
以上是生活随笔為你收集整理的ZooKeeper学习第七期--ZooKeeper一致性原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dra-tl00是什么型号
- 下一篇: MySQL数据库误删回滚怎么解决