ZAB協議和Paxos演算法

發表於2017-01-04

前言

在上一篇文章Paxos演算法淺析中主要介紹了Paxos一致性演算法應用的場景,以及對協議本身的介紹;Google Chubby是一個分散式鎖服務,其底層一致性實現就是以Paxos演算法為基礎的;但這篇檔案並不是介紹Chubby,而是介紹了一個和Chubby擁有類似功能的開放原始碼的分散式協調服務Zookeeper,以及Zookeeper資料一致性的核心演算法ZAB。

Zookeeper簡介

Zookeeper是一個分散式資料一致性的解決方案,分散式應用可以基於它實現諸如資料釋出/訂閱,負載均衡,命名服務,分散式協調/通知,叢集管理,Master選舉,分散式鎖和分散式佇列等功能。Zookeeper致力於提供一個高效能、高可用、且具有嚴格的順序訪問控制能力的分散式協調系統。
考慮到Zookeeper主要運算元據的狀態,為了保證狀態的一致性,Zookeeper提出了兩個安全屬性:
1.全序(Total order):如果訊息a在訊息b之前傳送,則所有Server應該看到相同的結果
2.因果順序(Causal order):如果訊息a在訊息b之前發生(a導致了b),並被一起傳送,則a始終在b之前被執行。
為了保證上述兩個安全屬性,Zookeeper使用了TCP協議和Leader
通過使用TCP協議保證了訊息的全序特性(先發先到),
通過Leader解決了因果順序問題:先到Leader的先執行,但是這樣的話Leader有可能出現出現網路中斷、崩潰退出與重啟等異常情況,這就有必要引入Leader選舉演算法。
而ZAB(Zookeeper Atomic Broadcast即Zookeeper原子訊息廣播協議)正是作為其資料一致性的核心演算法,下面介紹一下ZAB協議。

ZAB協議

ZAB協議包括兩種基本的模式:崩潰恢復和訊息廣播
當整個服務框架在啟動過程中,或是當Leader伺服器出現網路中斷崩潰退出與重啟等異常情況時,ZAB就會進入恢復模式並選舉產生新的Leader伺服器。
當選舉產生了新的Leader伺服器,同時叢集中已經有過半的機器與該Leader伺服器完成了狀態同步之後,ZAB協議就會退出崩潰恢復模式,進入訊息廣播模式。
當有新的伺服器加入到叢集中去,如果此時叢集中已經存在一個Leader伺服器在負責進行訊息廣播,那麼新加入的伺服器會自動進入資料恢復模式,找到Leader伺服器,並與其進行資料同步,然後一起參與到訊息廣播流程中去。
以上其實大致經歷了三個步驟:
1.崩潰恢復:主要就是Leader選舉過程
2.資料同步:Leader伺服器與其他伺服器進行資料同步
3.訊息廣播:Leader伺服器將資料傳送給其他伺服器

下面具體看看這三個步驟
1.訊息廣播
ZAB協議的訊息廣播過程使用的是一個原子廣播協議,類似二階段提交(2PC/3PC到底是啥),具體可以看來源網上的一張圖片:

客戶端的請求,Leader伺服器為其生成對於的Propose,並將其傳送給其他伺服器,然後再分別收集選票,最後進行提交;在廣播Propose之前,Leader會為這個Propose分配一個全域性單調遞增的唯一ID,稱之為事務ID(ZXID);由於ZAB協議需要保證每一個訊息嚴格的因果關係,因此必須將每一個Propose按照其ZXID的先後順序來進行排序與處理。
具體做法就是Leader為每一個Follower都各自分配一個單獨的佇列,然後將需要廣播的Propose依次放入佇列中。

2.崩潰恢復
訊息廣播中如果Leader出現網路中斷、崩潰退出與重啟等異常,將進入崩潰恢復,恢復的過程中有2個問題需要解決:
1.ZAB協議需要確保那些已經在Leader伺服器上提交的事務,最終被所有伺服器都提交
2.ZAB協議需要確保丟棄那些只在Leader伺服器上被提交的事務
針對以上兩個問題,如果讓Leader選舉演算法能夠保證新選出來的Leader伺服器擁有叢集中所有機器最高編號(ZXID)的Propose,那麼就可以保證這個新選出來的Leader一定具有所有已經提交的提案;如果讓具有最高編號的機器成為Leader,就可以省去Leader伺服器檢查Propose的提交和拋棄了。

3.資料同步
Leader伺服器會為每個Follower伺服器都準備一個佇列,並將那些沒有被各Follower同步的事務以propose訊息的形式逐個傳送給Follower伺服器,並在每個訊息的後面傳送一個commit訊息,表示提交事務;等到同步完成之後,leader伺服器會將該伺服器加入到真正的可用Follower列表中。
崩潰恢復中提到2個問題,看看如何解決ZAB協議需要確保丟棄那些只在Leader伺服器上被提交的事務:
事務編號ZXID被設計為一個64位的數字,低32位是一個簡單的遞增計數器,高32位是Leader週期的epoch編碼,每當選舉產生一個新的Leader伺服器,就會從這個Leader伺服器上取出本地日誌中最大事務propose的ZXID,然後解析出epoch,最後對epoch加1;低32位就從0開始重新生成新的ZXID。ZAB協議通過epoch編號來區分Leader週期變化的策略,來保證丟棄那些只在上一個Leader伺服器上被提交的事務。

Zab與Paxos

Zab的作者認為Zab與paxos並不相同,只所以沒有采用Paxos是因為Paxos保證不了全序順序:
Because multiple leaders can propose a value for a given instance two problems arise.
First, proposals can conflict. Paxos uses ballots to detect and resolve conflicting proposals.
Second, it is not enough to know that a given instance number has been committed, processes must also be able to fi gure out which value has been committed.
Paxos演算法的確是不關心請求之間的邏輯順序,而只考慮資料之間的全序,但很少有人直接使用paxos演算法,都會經過一定的簡化、優化。

Paxos演算法優化

Paxos演算法在出現競爭的情況下,其收斂速度很慢,甚至可能出現活鎖的情況,例如當有三個及三個以上的proposer在傳送prepare請求後,很難有一個proposer收到半數以上的回覆而不斷地執行第一階段的協議。因此,為了避免競爭,加快收斂的速度,在演算法中引入了一個Leader這個角色,在正常情況下同時應該最多隻能有一個參與者扮演Leader角色,而其它的參與者則扮演Acceptor的角色。
在這種優化演算法中,只有Leader可以提出議案,從而避免了競爭使得演算法能夠快速地收斂而趨於一致;而為了保證Leader的健壯性,又引入了Leader選舉,再考慮到同步的階段,漸漸的你會發現對Paxos演算法的簡化和優化已經和上面介紹的ZAB協議很相似了。

總結

Google的粗粒度鎖服務Chubby的設計開發者Burrows曾經說過:“所有一致性協議本質上要麼是Paxos要麼是其變體”。這句話還是有一定道理的,ZAB本質上就是Paxos的一種簡化形式。

 

相關文章