Zookeeper理解---ZAB协议
ZAB協議
- Zookeeper并不是完全采用Paxos算法,而是使用了一種稱為Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息廣播協議)作為數據一致性的核心算法,依據此算法來實現分布式數據一致性的解決。他是一種特別為Zookeeper設計的奔潰可恢復的原子消息廣播算法。
- ZAB協議的核心是定義了對應那些會改變Zookeeper服務器數據狀態的師傅請求的處理方式:
- 所有事務請求必須有一個全局唯一服務器來協調處理,這樣的服務器被稱為leader服務器
- 其他服務器成為follower服務器,leader服務器負責講一個客戶端事務請求轉換成一個事務Proposal(提議),并將改Proposal分發給集群中所有Follower服務器
- leader服務器等待所有Follower反饋,等待超過半數Follower進行了正確反饋
- leader就會再次向所有Follower發出Commons消息,要求將前一個Proposal進行提交
協議介紹
- ZAB包括兩種基本模式:
- 奔潰恢復: 當整個服務框架啟動過程中,或者leader節點出現網絡故障或者崩潰退出與重啟等異常情況時候,ZAB協議會進入恢復模式進行選舉產生新的Leader服務器,當選出來Leader并且同步了半數以上的Follower節點狀態(狀態同步就是數據同步)后,ZAB才退出恢復模式
- 消息廣播:過半數Follower都與Leader同步完成后,整個服務框架就可以進入消息廣播模式了。但一臺同樣遵循ZAB協議的節點加入后,此時已經有一個Leader節點,新加入的服務會自覺進入恢復模式,同步數據后加入廣播流程
- Leader節點作用在于接受客戶端事務請求后,會生成對應的事務提案并發起一輪廣播協議,如果集群中其他節點先收到客戶端事務請求,他會轉發給leader節點
- 關鍵字:過半數節點
消息廣播
- ZAB協議的消息廣播過程是使用的原子廣播協議,類似一個二階段提交的過程,上面一節提到過,就如下圖中所示
- 與二階段提交不同的是,ZAB的提交過程移除了中斷邏輯,也就是不存在應為單個節點沒回應ACK而中斷廣播的情況,所有Follower要么正常反饋,要么拋棄leader服務器,并且只需要過半數的Follower服務器訪客ACK后就開始提交事務Proposal,而不需要所有。這種情況有弊端:無法處理leader崩潰帶來的數據不一致問題(恢復模式解決此問題),并且整個消息廣播協議是有FIFO特性的TCP協議來進行網絡通信,能保證消息發送的順序
順序性保證
- 因為只有Leader服務器負責生產對應Proposal來進行廣播,并且廣播之前,leader會為每一個Proposal分配一個全局唯一遞增事務ID(即ZXID)。由此遞增ID就可以保證我們每一個Proposal嚴格按照ZXID順序來進行處理發送即可
- 處理好了leader發送順序,Follower如何保證接受到順序:廣播過程Leader會為每一個Follower分配一個單獨隊列,依次將Proposal放入隊列,并且依據ZXID順序FIFO策略進行消息發送,每個Follower接受到事務Proposal會以事務日志形式寫入本地磁盤,成功寫入后反饋給Leader服務器一個Ack響應。
- Leader收到超半數ACK后,廣播一個Commit消息給所有Follower服務器以通知進行事務提交,同事Leader自己也完成Commit。
奔潰恢復
- Leader節點奔潰后需要觸發選舉,選出新Leader,并讓所有節點能夠快速的感知到新的Leader服務器是哪個
基本特性
-
崩潰恢復可能出現兩種數據不一致的隱患, 針對這兩種情況ZAB需要保證的特性:
-
情況一: ZAB協議需要確保已經在Leader服務器上提交的服務最終被所有服務器都提交
-
事務在Leader服務器上被提交了,并且已經得到過半Follower服務器的ACK反饋,但在Commit消息發送給所有Follower機器之前Leader服務器掛了,如下圖:
-
上圖leader是Server1,已經廣播消息P1,P2,C1,P3和C2,當leader將C2(C2 是Commit of proposal2的縮寫)發出后崩潰,此時ZAB協議需要保證Proposal2最終能在所有服務器上被提交
-
情況二:ZAB需要確保丟棄那些只在Leader服務器上被提出的事務。
-
與之前相反的情況,奔潰恢復過程中出現一個需要被丟棄的案例,那么恢復后需要跳過次事務:
-
上圖Leader服務器Server1 提出一個事務Proposal3后就奔潰,其他follower都沒有收到這個事務,當Server1恢復再次加入集群,ZAB需要確保丟棄這個Proposal3
Leader選舉
- 根據以上兩種情況確保提交已經被Leader提交的事務Proposal同時丟棄被跳過的事情,需要ZAB必須有這樣的Leader選舉算法:
- 保證選舉出來的Leader服務器擁有集群中所有機器最高編號(最大ZXID)事務Proposal,那么可以把這這個新選舉出來的Leader一定具有所有已經提交的案例,并且可以省去服務器檢查proposal的提交和丟棄工作的這部操作,所有事務按最高ZXID節點擁有的數據為準。
數據同步
- Leader選舉后,Leader服務器為每一個Follower服務器準備一個隊列,將那些沒有被Follower服務器同步的事務以Proposal消息的方法逐個發給Follower服務器,并且在每個Proposal消息后緊接著發一個Commit消息,標識已經提交。等同步完成所有消息并且將數據應用到本地數據庫中后,leader會將Follower服務器加入到真正的可用Follower列表,并且開始之后的流程。
丟棄數據
- 如何處理需要被丟棄的Proposal,ZAB協議變化ZXID設計上解決這個問題:
- ZXID是一個64位的數據,低32位是一個單調遞增的計數器,針對每個事物請求計數器+1操作,高位32位代表Leader周期epoch的編號,每單選舉產生一個新的Leader服務器,就會從Leader服務器上去除其本地日志中最大事物Proposal的ZXID,
并從該ZXID中解析出上一次的epoch值,然后在這個基礎上+1,就用此編號作為新的epoch,就相當于每一個Leader都遞增1 的一個策略。ZAB協議通過epoch編號來區分Leader周期變化策略,能有效避免不同Leader服務器錯誤使用相同ZXID變化踢出不一樣事務Proposal的異常情況,對于識別崩潰后在恢復之后生成的Proposal非常有幫助。
結論
- 基于上面的策略,當一個包含上一個Leader周期中沒提交的事務Proposal的服務器復活的時候,肯定無法成為Leader,因為當前集群中包含一個Quorum集合,該集合中一定包含了更高epoch的事務Proposal,因此當前復活的節點事務Proposal肯定是舊的,無法成為Leader,當加入集群后,只能以Follow角色鏈接Leader服務器,接著Leader會根據自己服務器上最后被提交的Proposal來和Follower的Proposal對比,接著會按當前Leader的匹配要求同步當前Leader的數據(也就相當于回退)到一個確實已經被集群中過半集群提交的最新事務Proposal。
深入ZAB協議
- 上面部分介紹類ZAb協議大體內容以及實際運行中消息官博和奔潰恢復這兩個基本模式。以下從系統模型,問題描述,算法描述,運行分析深入理解ZAB協議
系統模型
- 分布式系統模型中我門將每個server看作是一個進程p,那么可以用集合∏={P1,P2,…,Pn}來表示分布式系統,每個進程都具有格子的存儲設備,就好比緩存隔離,個進程直接互相通信來實現消息傳遞。每個進程都肯奔潰或重啟,奔潰我們稱為down踢出集合∏,恢復存活狀態我們稱為up重新加入∏,只要∏ 集合中有超過半數的是up狀態就可以進行消息廣播,我們將這樣一個自集合稱為Quorum(上文提到過)之后用Q表示,并假設Q已經存在滿足以下:
完整性
- 進程P_j如果收到來自進程P_i的消息m,那么p_i一定發送來消息m
前置性
- 進程P_j收到來消息m,那么存在這樣的消息m’:如果消息m’ 是消息m的前置,那么P_j務必先收到m’,這種關系表示:m’ < m
問題描述
- Zookeeper需要解決一系列諸如可靠配置存儲,運行時狀態記錄等分布式協調服務,因此必須具備高吞吐量,低延遲特性,能很好的在高并發下完成分布式數據一致性處理,同時能優雅處理運行時故障,快速恢復
- ZAB核心是只有一個主進程,如果主進程掛了就重選,主進程選舉與消息廣播密切相關。隨著時間推移可能出現無限多個主進程并構成一個主進程序列:P_1,P_2,P_3…P_e-1,P_e其中P_e ? ∏ ,e表示主進程序列好嗎,我們這里稱他為主進程周期。
- 對于以上序列中任意一個如果存在e < e’,那么我們就說P_e 是P_e’ 之前的主進程,使用 P_e < P_e’ ,他門是同一個進程只不過是不同周期而已
主進程周期
- 用以上 P_e < P_e’ 的案例來解釋,就比如進程P_e周期中主節點是L_e,此時主節點L_e 掛掉了,重新選出L_e’(e’=e+1)就得到了P_e’,其實是同一個進程只是表示他在不同的Leader周期下而已,我們表示為e < e’
事物
- 幾個概念,我們假設各個進程中有一個transactions(v,z)這樣的函數,用來實現主進程堆狀態變更的廣播,其中參數v:事物內容,z:事物表示,而每一個事物表示z=<e,c>,e表示進程周期,c表示周期內事物技術,也就是我們上文中提到的epoch(z)表示事物標識中的主進程周期epoch,counter(z)表示事務計數器
- 每個新事務c都遞增,實際運行中事務z 優與事務 z’ ,有兩種情況:
- epoch(z) < epoch(z’) :z是上一個主進程周期中的事務,z’是重新選舉后的事務
- epoch(z) = epoch(z’) 且 counter(z) < counter(z’) 同一個主進程周期,但是z’事務序列號更大
算法描述
- ZAB協議注意包括消息廣播和崩潰恢復,進一步可以分三個階段:發現(Discovery),同步(Synchronization),廣播(Broadcast),先定義如下專用標識和屬于
| F.p | Follower f處理過的最后一個事務Proposal |
| F.zxid | Follower f處理過的歷史事務Proposal中最后一個Proposal的事務表示ZXID |
| h_f | 每一個Follower f通常都已經處理(接受)了不少事務Proposal,并且會有一個針對已經處理過的事務的集合,將其表示為Hf,表示Follower f已經處理過的事務的序列 |
| I_e | 初始化歷史記錄,在某個主進程周期epoch中,當準Leader完成階段一之后,此時他的h_f就被標記為I_e |
階段一:發現
-
主要是Leader選舉過程,用于分布式進程中選舉主進程,準Leader L,和Follower F工作流程:(姑且認為Leader L是隨機出來的)
- 步驟F.1.1 Follower F將自己最后接受的事務Proposal的epoch值CEPOCH(F.p)發送給準Leader L
- 步驟L.1.1 當接受來自過半的Follower的Cepoch(F.p)消息后,準Leader L會生成NEWEPOCH(e’),這個epoch的值e’ 是Leader L從CEPOCH(F.p)消息中選取的最大epoch,然后對其+1得到e’(就是獲取最大一個ZXID的值從中得到epoch,然后在+1)
- 步驟F1.2 當Follower 接受到來自準Leader L的NEWEPOCH(e’)消息后,如果其檢測到當前CEPOCH(F.p)小于e’,那么就將CEPOCH(F.p)=e’,同時向這個準Leader L反饋Ack消息。這個反饋消息(ACK-E(F.p, h_f)),包含當前該Follower的epoch(F.p)也就是最后一個事務的信息,以及該Follower的歷史事務Proposal列表:h_f
-
當Leader L接受到來自過半Follower的確認消息Ack后,Leader L就會從這過半服務器中選取出一個Follower F,使用他的I_e最為初始化事務結婚I_e’
-
關于這個Follower F的選取對于Quorum中其他任意一個Follower F’ ,F需要滿足以下兩個條件中的一個:
階段二:同步
- 發現流程后,進入同步節點,此時Leader L與Follower F流程如下:
- L.2.1 Leader 會將e’和I_e’以NEWLEADER(e’, I_e’)消息的形式發送給Quorum中的Follower(將新的epoch主節點序列號和 最全的事務列表同步)
- 步驟F.2.1 當Follower接受到來自Leader L的NEWLEADER(e’, I_e’)消息后,如果Follower發現CEPOCH(F.p)≠ e’,那么直接跳過進入下一輪循環因為此時Follower 發現自己還在上一輪,或者更上一個的同步中,因為需要在發現階段就已經將epoch修改為e’,他可能還在發現階段屬于另外一半還沒收到Leader L的NEWEPOCH(e’)消息的節點
- 如果CEPOCH(F.p) = e’ ,那么Follower會執行事務應用操作,具體的對每一個事務Proposal:<v, z > ? I_e’, Follower都會接受<e’, <v, z>>。最后Follower會反饋給Leader,表示字節已經接受并處理來所有I_e’中的事務,(此處的意思是Leader L節點將最新的一份Proposal列表的信息以及最新的epoch數據發送給每一個Follower節點讓他去同步修改,如果Follower中的Proposal是在其中,那么我就將之前Proposal里面的epoch值也就是e修改為新的epoch值也就是e’)
- 步驟L.2.2 當Leader 接受到來自過半Follower 針對NEWWLEADER(e’, I_e’)的反饋消息后,就會向所有Follower發送消息Commit,至此Leader 完成階段二
- 步驟F.2.2 當Follower收到來自Leader的Commit后,就會一次處理并提交所有在I_e’中為未理的事務,至此Follower完成階段二
階段三:廣播
- 完成同步后ZAB開始正式工作,接受客戶端新事務請求,進行廣播流程
- 步驟L.3.1 Leader L接受到客戶端新的事務請求,會生成對應的事務Proposal,并且根據ZXID順序向Follower發送提案<e’, <v, z>>,其中epoch(z) = e’,z就是ZXID,64位,低32 是Proposal事務序列號,高32位是Leader周期的epoch序列號
- 步驟F.3.1 Follower根據消息接收先后順序處理來自Leader事務的Proposal,并將他們追加到h_f中去,之后在反饋給Leader
- 步驟L.3.1 當Leader接收到來自過半Follower針對事務Proposal<e’, <v, z>>的Ack消息后,就發送Commit<e’, <v, z>>消息給所有Follower,要求他們進行事務的提交
- 步驟F.3.2 當Follow F接受到來自Leader的Commit<e’, <v, z>> 就會開始提交Proposal<e’, <v, z>>,需要主要,此時該Follower F必定已經提交來事務Proposal<v’, z’ >,其中<v’, z’ > ? h_f, z’ < z
總結
如下圖是以上三個流程總結,各個消息說明如下:
- CEPOCH:Follower進程向準Leader發送字節處理過的最后一個事務Proposal的epoch值
- NEWEPOCH:準Leader根據接受到的各進程的epoch生成新一輪的周期epoch值
- ACK-E:Follower進程反饋Leader進程發來的NEWEPOCH消息
- NEWLEADER: 準Leader進程確認字節領導地位,并發生NEWLEADER消息給各個進程
- ACK-LD:Follower進程反饋Leader進程發來的NEWLEADER消息
- COMMIT-LD:要求Follower進程提交相應的歷史事務Proposal
- PROPOSE:Leader進程生成一個針對客戶端事務請求的Proposal
- ACK:Follower進程反饋Leader進程發來的PROPOSAL消息
- COMMIT:Leader發送COMMIT消息,要求所有進程提交事務PROPOSE
上一篇:Zookeeper–簡介
下一篇:Zookeeper–ZAB與Paxos算法聯系與區別
總結
以上是生活随笔為你收集整理的Zookeeper理解---ZAB协议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 牛角刮痧板哪种牛角最好
- 下一篇: Zookeeper--ZAB与Paxos