《從Paxos到ZooKeeper分布式一致性原理與實(shí)踐》讀書筆記(二) - ZAB協(xié)議

一、概述

??ZAB(ZooKeeper Atomic Broadcast)協(xié)議是為分布式協(xié)調(diào)服務(wù)ZooKeeper專門設(shè)計(jì)的一種支持崩潰恢復(fù)的原子廣播協(xié)議。

二、ZAB協(xié)議的核心

??ZAB 協(xié)議的核心是定義了對(duì)于那些會(huì)改變 ZooKeeper 服務(wù)器數(shù)據(jù)狀態(tài)的事務(wù)請(qǐng)求的處理方式,即:所有事務(wù)請(qǐng)求必須由一個(gè)全局唯一的服務(wù)器來(lái)協(xié)調(diào)處理,這樣的服務(wù)器被稱為 Leader服務(wù)器,而余下的其他服務(wù)器則成為 Follower 服務(wù)器。Leader 服務(wù)器負(fù)責(zé)將一個(gè)客戶端事務(wù)請(qǐng)求轉(zhuǎn)換成一個(gè)事務(wù) Proposal(提議),并將該 Proposal 分發(fā)給集群中所有的Follower 服務(wù)器。之后 Leader 服務(wù)器需要等待所有 Follower 服務(wù)器的反饋,一旦超過(guò)半數(shù)的 Follower 服務(wù)器進(jìn)行了正確的反饋后,那么 Leader 就會(huì)再次向所有的 Follower服務(wù)器分發(fā)Commit消息,要求其將前一個(gè)Proposal進(jìn)行提交。

三、ZAB協(xié)議實(shí)現(xiàn)分布式數(shù)據(jù)一致性

  1. 基于ZAB協(xié)議,ZooKeeper實(shí)現(xiàn)了一種主備模式的系統(tǒng)架構(gòu)來(lái)保持集群中各副本之間數(shù)據(jù)的一致性。具體的,ZooKeeper使用一個(gè)單一的主進(jìn)程來(lái)接收并處理客戶端的所有事務(wù)請(qǐng)求,并采用ZAB的原子廣播協(xié)議,將服務(wù)器數(shù)據(jù)的狀態(tài)變更以事務(wù)Proposal的形式廣播到所有的副本進(jìn)程上去。

  2. 針對(duì)分布式環(huán)境中,在變更順序執(zhí)行的一些狀態(tài)時(shí),其前后會(huì)存在一定的依賴關(guān)系,有些狀態(tài)變更必須依賴于比它早生成的那些狀態(tài)變更的情況(例如變更C需要依賴變更A和變更B)。要求ZAB協(xié)議必須能夠保證一個(gè)全局的變更序列被順序應(yīng)用,也就是說(shuō),ZAB協(xié)議需要保證如果一個(gè)狀態(tài)變更已經(jīng)被處理了,那么所有其依賴的狀態(tài)變更都應(yīng)該已經(jīng)被提前處理掉了。

  3. 當(dāng)主進(jìn)程出現(xiàn)崩潰退出或重啟時(shí),ZAB 協(xié)議就會(huì)進(jìn)入恢復(fù)模式并選舉產(chǎn)生新的 Leader 服務(wù)器。當(dāng)選舉產(chǎn)生了新的Leader服務(wù)器,同時(shí)集群中已經(jīng)有過(guò)半的機(jī)器與該Leader服務(wù)器完成了狀態(tài)同步之后,ZAB協(xié)議就會(huì)退出恢復(fù)模式。其中,所謂的狀態(tài)同步是指數(shù)據(jù)同步,用來(lái)保證集群中存在過(guò)半的機(jī)器能夠和Leader服務(wù)器的數(shù)據(jù)狀態(tài)保持一致。

四、ZAB協(xié)議的模式

1. 消息廣播

??ZAB協(xié)議的消息廣播過(guò)程使用的是一個(gè)原子廣播協(xié)議,類似于一個(gè)二階段提交過(guò)程(見(jiàn)底部備注)。針對(duì)客戶端的事務(wù)請(qǐng)求,Leader服務(wù)器會(huì)為其生成對(duì)應(yīng)的事務(wù)Proposal,并將其發(fā)送給集群中其余所有的機(jī)器,然后再分別收集各自的選票,最后進(jìn)行事務(wù)提交,如圖所示就是ZAB協(xié)議消息廣播流程的示意圖。


廣播示意圖

??ZAB 協(xié)議中涉及的二階段提交過(guò)程則與正真的二階段提交過(guò)程略有不同。在 ZAB 協(xié)議的二階段提交過(guò)程中,移除了中斷邏輯,所有的 Follower 服務(wù)器要么正常反饋 Leader 提出的事務(wù) Proposal,要么就拋棄Leader服務(wù)器。同時(shí),ZAB協(xié)議將二階段提交中的中斷邏輯移除意味著我們可以在過(guò)半的 Follower 服務(wù)器已經(jīng)反饋 Ack 之后就開(kāi)始提交事務(wù) Proposal 了,而不需要等待集群中所有的Follower服務(wù)器都反饋?lái)憫?yīng)。

??在整個(gè)消息廣播過(guò)程中,Leader服務(wù)器會(huì)為每個(gè)事務(wù)請(qǐng)求生成對(duì)應(yīng)的Proposal來(lái)進(jìn)行廣播,并且在廣播事務(wù)Proposal之前,Leader服務(wù)器會(huì)首先為這個(gè)事務(wù)Proposal分配一個(gè)全局單調(diào)遞增的唯一ID,我們稱之為事務(wù)ID(即ZXID)。

??由于ZAB協(xié)議需要保證每一個(gè)消息嚴(yán)格的因果關(guān)系,因此必須將每一個(gè)事務(wù)Proposal按照其ZXID的先后順序來(lái)進(jìn)行排序與處理。具體的,在消息廣播過(guò)程中,Leader服務(wù)器會(huì)為每一個(gè)Follower服務(wù)器都各自分配一個(gè)單獨(dú)的隊(duì)列,然后將需要廣播的事務(wù) Proposal 依次放入這些隊(duì)列中去,并且根據(jù) FIFO策略進(jìn)行消息發(fā)送。每一個(gè)Follower服務(wù)器在接收到這個(gè)事務(wù)Proposal之后,都會(huì)首先將其以事務(wù)日志的形式寫入到本地磁盤中去,并且在成功寫入后反饋給Leader服務(wù)器一個(gè)Ack響應(yīng)。當(dāng)Leader服務(wù)器接收到超過(guò)半數(shù)Follower的Ack響應(yīng)后,就會(huì)廣播一個(gè)Commit消息給所有的Follower服務(wù)器以通知其進(jìn)行事務(wù)提交,同時(shí)Leader自身也會(huì)完成對(duì)事務(wù)的提交,而每一個(gè)Follower服務(wù)器在接收到Commit消息后,也會(huì)完成對(duì)事務(wù)的提交。
注意:在這種簡(jiǎn)化了的二階段提交模型下,無(wú)法處理Leader服務(wù)器崩潰退出而帶來(lái)的數(shù)據(jù)不一致問(wèn)題的,因此在ZAB協(xié)議中添加了另一個(gè)模式 - 崩潰恢復(fù)模式來(lái)解決這個(gè)問(wèn)題。

2. 崩潰恢復(fù)

??當(dāng)整個(gè)服務(wù)框架在啟動(dòng)過(guò)程中,或是當(dāng)Leader服務(wù)器出現(xiàn)網(wǎng)絡(luò)中斷、崩潰退出與重啟等異常情況時(shí),ZAB 協(xié)議就會(huì)進(jìn)入恢復(fù)模式并選舉產(chǎn)生新的 Leader 服務(wù)器。當(dāng)選舉產(chǎn)生了新的Leader服務(wù)器,同時(shí)集群中已經(jīng)有過(guò)半的機(jī)器與該Leader服務(wù)器完成了狀態(tài)同步之后,ZAB協(xié)議就會(huì)退出恢復(fù)模式。其中,狀態(tài)同步是指數(shù)據(jù)同步,用來(lái)保證集群中存在過(guò)半的機(jī)器能夠和Leader服務(wù)器的數(shù)據(jù)狀態(tài)保持一致。

崩潰恢復(fù)過(guò)程存在隱患的處理

1.ZAB協(xié)議需要確保那些已經(jīng)在Leader服務(wù)器上提交的事務(wù)最終被所有服務(wù)器都提交。
??假設(shè)一個(gè)事務(wù)在 Leader 服務(wù)器上被提交了,并且已經(jīng)得到過(guò)半 Follower 服務(wù)器的Ack反饋,但是在它將Commit消息發(fā)送給所有Follower機(jī)器之前,Leader服務(wù)器掛了,

image.png

??圖中的消息C2就是一個(gè)典型的例子:在集群正常運(yùn)行過(guò)程中的某一個(gè)時(shí)刻,Server1 是 Leader 服務(wù)器,其先后廣播了消息 P1、P2、C1、P3 和 C2,其中,當(dāng)Leader服務(wù)器將消息C2(C2是Commit Of Proposal2的縮寫,即提交事務(wù)Proposal2)發(fā)出后就立即崩潰退出了。針對(duì)這種情況,ZAB協(xié)議就需要確保事務(wù)Proposal2最終能夠在所有的服務(wù)器上都被提交成功,否則將出現(xiàn)不一致。

2.ZAB協(xié)議需要確保丟棄那些只在Leader服務(wù)器上被提出的事務(wù)
??如果在崩潰恢復(fù)過(guò)程中出現(xiàn)一個(gè)需要被丟棄的提案,那么在崩潰恢復(fù)結(jié)束后需要跳過(guò)該事務(wù)Proposal,如圖所示。

image.png

??假設(shè)初始的 Leader 服務(wù)器 Server1 在提出了一個(gè)事務(wù)Proposal3 之后就崩潰退出了,從而導(dǎo)致集群中的其他服務(wù)器都沒(méi)有收到這個(gè)事務(wù)Proposal。于是,當(dāng) Server1 恢復(fù)過(guò)來(lái)再次加入到集群中的時(shí)候,ZAB 協(xié)議需要確保丟棄Proposal3這個(gè)事務(wù)。

??結(jié)合上面提到的這兩個(gè)崩潰恢復(fù)過(guò)程中需要處理的特殊情況,就決定了 ZAB 協(xié)議必須設(shè)計(jì)這樣一個(gè) Leader 選舉算法:能夠確保提交已經(jīng)被 Leader 提交的事務(wù) Proposal,同時(shí)丟棄已經(jīng)被跳過(guò)的事務(wù)Proposal。針對(duì)這個(gè)要求,如果讓Leader選舉算法能夠保證新選舉出來(lái)的Leader服務(wù)器擁有集群中所有機(jī)器最高編號(hào)(即ZXID最大)的事務(wù)Proposal,那么就可以保證這個(gè)新選舉出來(lái)的Leader一定具有所有已經(jīng)提交的提案。更為重要的是,如果讓具有最高編號(hào)事務(wù) Proposal 的機(jī)器來(lái)成為 Leader,就可以省去 Leader 服務(wù)器檢查Proposal的提交和丟棄工作的這一步操作了。

數(shù)據(jù)同步

??完成Leader選舉之后,在正式開(kāi)始工作(即接收客戶端的事務(wù)請(qǐng)求,然后提出新的提案)之前,Leader服務(wù)器會(huì)首先確認(rèn)事務(wù)日志中的所有Proposal是否都已經(jīng)被集群中過(guò)半的機(jī)器提交了,即是否完成數(shù)據(jù)同步。

(1)正常情況下的數(shù)據(jù)同步

??所有正常運(yùn)行的服務(wù)器,要么成為 Leader,要么成為 Follower 并和 Leader 保持同步。Leader服務(wù)器需要確保所有的Follower服務(wù)器能夠接收到每一條事務(wù)Proposal,并且能夠正確地將所有已經(jīng)提交了的事務(wù)Proposal應(yīng)用到內(nèi)存數(shù)據(jù)庫(kù)中去。具體的,Leader服務(wù)器會(huì)為每一個(gè)Follower服務(wù)器都準(zhǔn)備一個(gè)隊(duì)列,并將那些沒(méi)有被各Follower服務(wù)器同步的事務(wù)以Proposal消息的形式逐個(gè)發(fā)送給Follower服務(wù)器,并在每一個(gè)Proposal消息后面緊接著再發(fā)送一個(gè)Commit消息,以表示該事務(wù)已經(jīng)被提交。等到Follower服務(wù)器將所有其尚未同步的事務(wù) Proposal 都從 Leader 服務(wù)器上同步過(guò)來(lái)并成功應(yīng)用到本地?cái)?shù)據(jù)庫(kù)中后,Leader服務(wù)器就會(huì)將該Follower服務(wù)器加入到真正的可用Follower列表中,并開(kāi)始之后的其他流程。

(2)處理丟棄的事務(wù)Proposal

??在ZAB協(xié)議的事務(wù)編號(hào)ZXID設(shè)計(jì)中,ZXID是一個(gè)64位的數(shù)字,其中低 32 位可以看作是一個(gè)簡(jiǎn)單的單調(diào)遞增的計(jì)數(shù)器,針對(duì)客戶端的每一個(gè)事務(wù)請(qǐng)求,Leader服務(wù)器在產(chǎn)生一個(gè)新的事務(wù)Proposal的時(shí)候,都會(huì)對(duì)該計(jì)數(shù)器進(jìn)行加1操作;而高32位則代表了Leader周期epoch的編號(hào),每當(dāng)選舉產(chǎn)生一個(gè)新的Leader服務(wù)器,就會(huì)從這個(gè)Leader服務(wù)器上取出其本地日志中最大事務(wù)Proposal的ZXID,并從該ZXID中解析出對(duì)應(yīng)的epoch值,然后再對(duì)其進(jìn)行加1操作,之后就會(huì)以此編號(hào)作為新的epoch,并將低32位置0來(lái)開(kāi)始生成新的ZXID。ZAB協(xié)議中的這一通過(guò)epoch編號(hào)來(lái)區(qū)分 Leader 周期變化的策略,能夠有效地避免不同的 Leader 服務(wù)器錯(cuò)誤地使用相同的ZXID編號(hào)提出不一樣的事務(wù)Proposal的異常情況,這對(duì)于識(shí)別在Leader崩潰恢復(fù)前后生成的Proposal非常有幫助,大大簡(jiǎn)化和提升了數(shù)據(jù)恢復(fù)流程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容