前面介紹了ZooKeeper的基本知識,這一節咱們介紹一下ZooKeeper使用的協議。只有瞭解了ZooKeeper的協議,才能更好得理解ZooKeeper源代碼的實現。ZooKeeper使用的是Zab(ZooKeeper Atomic Broadcast)協議,它是基於Paoxs算法實現的。因此這一節咱們按照這個順序來說解:html
Paoxs算法算法
首先看一下Paoxs算法,通常說到zookeeper,咱們都會提起Paoxs算法和Lesile Lamport.promise
Paoxs算法是zookeeper的靈魂,這個算法是Leslie Lamport在1990年提出的一種基於消息傳遞的一致性算法.Paxos 算法解決的問題是一個分佈式系統如何就某個值(決議)達成一致。在ZooKeeper中的應用場景就是Leader選舉。安全
該算法由Leslie於1990年在文章The Part-Time Parliament中首次提出,可是這篇文章至關的晦澀難懂(也有一些軼事,能夠看文章連接中Leslie本身寫的內容),因而,Lesilie在2001年寫下了Paxos Made Simple.他對此解釋道:app
At the PODC 2001 conference, I got tired of everyone saying how difficult it was to understand the Paxos algorithm, published in [122]. Although people got so hung up in the pseudo-Greek names that they found the paper hard to understand, the algorithm itself is very simple. So, I cornered a couple of people at the conference and explained the algorithm to them orally, with no paper. When I got home, I wrote down the explanation as a short note, which I later revised based on comments from Fred Schneider and Butler Lampson. The current version is 13 pages long, and contains no formula more complicated than n1 > n2. less
Paxos Made Simple的abstract只有一句話:分佈式
The Paxos algorithm, when presented in plain English, is very simple.ide
在上文中是這樣描述Paoxs算法執行過程的:性能
Phase 1.優化
(a) A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors.
(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered proposal (if any) that it has accepted.
Phase 2.
(a) If the proposer receives a response to its prepare requests (numbered n) from a majority of acceptors, then it sends an accept request to each of those acceptors for a proposal numbered n with a value v, where v is the value of the highest-numbered proposal among the responses, or is any value if the responses reported no proposals.
(b) If an acceptor receives an accept request for a proposal numbered n, it accepts the proposal unless it has already responded to a prepare request having a number greater than n.
這幾乎就是Paxos的所有了. 這裏就不一句一句翻譯了。
Zab協議
Zab是一個高性能的廣播協議,主要用於主備系統,它是專門爲ZooKeeper設計的。Zab協議的詳細內容請參考論文《Zab: High-performance broadcast for primary-backup systems》。
ZAB相比Paxos的優勢有:
Paxos的一致性不能達到ZooKeeper的要求。由於Paoxs只是保證最終一致性,若是處理的請求之間有依賴關係,利用Paoxs處理的時候可能知足不了這些依賴關係。舉個例子:假設一開始Paxos系統中的leader是P1,它發起了兩個事務<t1, v1>(表示序號爲t1的事務要寫的值是v1)和<t2, v2>,過程當中掛了。新來個leader是P2,它發起了事務<t1, v1'>。然後又來個新leader是P3,它彙總了一下,得出最終的執行序列<t1, v1'>和<t2, v2>,即P2的t1在前,P1的t2在後。對應到ZooKeeper中的操做,P1對應的事務t1要建立"/a",事務t2要建立"/a/test",而P2的事務t1要建立"/b",P3彙總了以後得出的結論是先建立"/b",再建立"/a/test"。而對於ZooKeeper中的建立操做,只有父節點已經存在的狀況下才能建立子節點,也即只有先成功建立了"/a",接下來建立"/a/test"才能成功,因此建立完"/b"以後再建立"/a/test"就會失敗,這不是咱們但願的結果。
爲了保證這一點,ZAB要保證同一個leader的發起的事務要按順序被apply,同時還要保證只有先前的leader的全部事務都被apply以後,新選的leader才能發起新的事務。ZAB的核心思想,形象的說就是保證任意時刻只有一個節點是leader,全部更新事務都由leader發起去更新全部複本(稱爲follower),更新時用的就是兩階段提交協議,只要多數節點prepare成功,就通知他們commit。各follower要按當初leader讓他們prepare的順序來apply事務。由於ZAB處理的事務永遠不會回滾,ZAB的2階段提交作了點優化,多個事務只要通知zxid最大的那個commit,以前的各follower會通通commit。
剩下的就是怎麼來保證leader的可靠性,由於leader是會crash的,因此引入了leader選舉機制。leader選舉是基於Paoxs協議的,成爲leader的條件是必需要有一個多數派支持,此外還須要知道如下知識:
Leader選舉遇到的最大問題是:新Leader是否要繼續老Leader的狀態。這裏要按老Leader Crash的時機分兩種狀況:
第一種狀況,這些數據只有老Leader本身知道,當老Leader重啓後,須要與新Leader同步並把這些數據從本地刪除,以維持狀態一致。
第二種狀況,新Leader應該能經過一個多數派得到老Leader提交的最新數據。
老Leader重啓後,可能還會認爲本身是Leader,可能會繼續發送未完成的請求,從而由於兩個Leader同時存在致使算法過程失敗,ZooKeeper的解決辦法是把Leader信息加入每條消息的id中,Zookeeper中稱爲zxid,zxid爲一64位數字,高32位爲leader信息又稱爲epoch,每次leader轉換時遞增;低32位爲消息編號,Leader轉換時應該從0從新開始編號。經過zxid,Follower能很容易發現請求是否來自老Leader,從而拒絕老Leader的請求。
綜上可見,Zab協議實際上仍是基於Paoxs衍生出來的,Paoxs中沒有保證請求之間的邏輯順序,只考慮數據的全序,Zab在這方面進行了完善補充,同時因爲leader的存在,簡化了Paoxs的二段提交爲一段提交(Phase2),最後爲了確保leader的可靠性,又基於Paoxs協議實現了leader的選舉機制。