孫玄/陳東:聊一聊ZooKeeper的順序一致性

孫玄:【架構之美】微信公衆號作者,畢業於浙江大學,前轉轉公司首席架構師,大中後臺技術負責人;前58集團技術委員會主席,高級系統架構師;前百度資深研發工程師;


江帥帥:【江帥帥】微信公衆號作者,擅長系統架構設計,大數據,運維等技術領域;對大中後臺技術有豐富經驗;曾擔任懷致科技
CTO,並還在東軟集團、中國移動、多迪集團等企業中任職過相關技術負責人。

ZooKeeper作爲分佈式應用系統協調服務,在分佈式系統中的應用非常廣泛,在某些業務場景下甚至可以作爲註冊中心、分佈式鎖來使用。ZooKeeper之所以能有如此廣泛的應用,與它良好的數據一致性保障機制是分不開的。我們都知道ZooKeeper專門設計了Zab(Zookeeper Atomic Broadcast)協議作爲其數據一致性協議。

利用Zab協議的數據寫入由Leader結點協調,使用兩階段提交的方式,達到數據的最終一致性。爲什麼是最終一致性呢?我們先了解下兩階段的過程,如圖一所示:

在這裏插入圖片描述
數據寫入過程如下:

第一階段:每次的數據寫入事件作爲提案廣播給所有Follower結點;可以寫入的結點返回確認信息ACK;
第二階段:Leader收到一半以上的ACK信息後確認寫入可以生效,向所有結點廣播COMMIT將提案生效。

根據寫入過程的兩階段的描述,我們知道ZooKeeper保證的是最終一致性,即Leader向客戶端返回寫入成功後,可能有部分Follower還沒有寫入最新的數據,所以是最終一致性。

我們都知道ZooKeeper保證的最終一致性也叫順序一致性,即每個結點的數據都是嚴格按事務的發起順序生效的。

ZooKeeper 是如何保證事務順序的呢?

這裏需要了解下它的事務ID(ZXID),之前的文章介紹過ZooKeeper的在選舉時通過比較各結點的ZXID和機器ID選出新的注結點的。ZXID由Leader節點生成,有新寫入事件時,Leader生成新ZXID並隨提案一起廣播,每個結點本地都保存了當前最近一次事務的ZXID,ZXID是遞增的,所以誰的ZXID越大,就表示誰的數據是最新的。

ZXID的生成規則如下圖所示:
在這裏插入圖片描述
**任期:**完成本次選舉後,直到下次選舉前,由同一Leader負責協調寫入;
事務計數器:單調遞增,每生效一次寫入,計數器加一。

可以看到,ZXID的低32位是計數器,所以同一任期內,ZXID是連續的,每個結點又都保存着自身最新生效的ZXID,通過對比新提案的ZXID與自身最新ZXID是否相差“1”,來保證事務嚴格按照順序生效的。

我們都知道ZooKeeper集羣的寫入是由Leader結點協調的,真實場景下寫入會有一定的併發量,那Zab協議的兩階段提交是如何保證事務嚴格按順序生效的呢?在本章介紹兩階段提交的部分描述了Leader在收到半數以上ACK後會將提案生效並廣播給所有Follower結點。

Leader爲了保證提案按ZXID順序生效,使用了一個ConcurrentHashMap,記錄所有未提交的提案,命名爲outstandingProposals,key爲ZXID,Value爲提案的信息。對 outstandingProposals 的訪問邏輯如下:

  1. 每發起一個提案,會將提案的ZXID和內容放到outstandingProposals中,作爲待提交的提案;
  2. 收到Follower的ACK信息後,根據ACK中的ZXID從outstandingProposals中找到對應的提案,對ACK計數;
  3. 執行tryToCommit嘗試將提案提交,判斷流程如下:
    3.1 判斷當前ZXID之前是否還有未提交提案,如果有,當前提案暫時不能提交;
    3.2 判斷提案是否收到半數以上ACK,如果達到半數則可以提交;
    3.3 如果可以提交,將當前ZXID從outstandingProposals中清除並向Followers廣播提交當前提案;

Leader是如何判斷當前ZXID之前是否還有未提交提案的呢?由於前提是保證順序提交的,所以Leader只需判斷outstandingProposals裏,當前ZXID的前一個ZXID是否存在,代碼如下:
在這裏插入圖片描述
所以ZooKeeper是通過兩階段提交保證數據的最終一致性,並且通過嚴格的按照ZXID的順序生效提案保證其順序一致性的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章