日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

本文作者:何建輝(公眾號:org_yijiaoqian)

本文 GitHub org_hejianhui/JAVAStudy 已收錄,有我的系列文章。

前言

  • Zookeeper特性與節(jié)點(diǎn)說明
  • Zookeeper客戶端使用與集群原理
  • Zookeeper典型使用場景實(shí)踐

前三篇講了Zookeeper的特性、客戶端使用和集群原理、典型使用場景實(shí)踐,本篇重點(diǎn)深入了解ZAB協(xié)議以及源碼實(shí)現(xiàn)的解析。

Zookeeper ZAB協(xié)議

什么是Zab協(xié)議?

Zab協(xié)議的全稱是 Zookeeper Atomic Broadcast (Zookeeper原子廣播)。

Zookeeper 是通過 Zab 協(xié)議來保證分布式事務(wù)的最終一致性。

  1. Zab協(xié)議是為分布式協(xié)調(diào)服務(wù)Zookeeper專門設(shè)計(jì)的一種 支持崩潰恢復(fù) 的 原子廣播協(xié)議 ,是Zookeeper保證數(shù)據(jù)一致性的核心算法。Zab借鑒了Paxos算法,但又不像Paxos那樣,是一種通用的分布式一致性算法。它是特別為Zookeeper設(shè)計(jì)的支持崩潰恢復(fù)的原子廣播協(xié)議
  2. 在Zookeeper中主要依賴Zab協(xié)議來實(shí)現(xiàn)數(shù)據(jù)一致性,基于該協(xié)議,zk實(shí)現(xiàn)了一種主備模型(即Leader和Follower模型)的系統(tǒng)架構(gòu)來保證集群中各個(gè)副本之間數(shù)據(jù)的一致性。這里的主備系統(tǒng)架構(gòu)模型,就是指只有一臺(tái)客戶端(Leader)負(fù)責(zé)處理外部的寫事務(wù)請求,然后Leader客戶端將數(shù)據(jù)同步到其他Follower節(jié)點(diǎn)。

Zookeeper 客戶端會(huì)隨機(jī)的鏈接到 zookeeper 集群中的一個(gè)節(jié)點(diǎn),如果是讀請求,就直接從當(dāng)前節(jié)點(diǎn)中讀取數(shù)據(jù);如果是寫請求,那么節(jié)點(diǎn)就會(huì)向 Leader 提交事務(wù),Leader 接收到事務(wù)提交,會(huì)廣播該事務(wù),只要超過半數(shù)節(jié)點(diǎn)寫入成功,該事務(wù)就會(huì)被提交。

Zab 協(xié)議實(shí)現(xiàn)的作用

  1. 使用一個(gè)單一的主進(jìn)程(Leader)來接收并處理客戶端的事務(wù)請求(也就是寫請求),并采用了Zab的原子廣播協(xié)議,將服務(wù)器數(shù)據(jù)的狀態(tài)變更以 事務(wù)proposal (事務(wù)提議)的形式廣播到所有的副本(Follower)進(jìn)程上去。
  2. 保證一個(gè)全局的變更序列被順序引用

Zookeeper是一個(gè)樹形結(jié)構(gòu),很多操作都要先檢查才能確定是否可以執(zhí)行,比如P1的事務(wù)t1可能是創(chuàng)建節(jié)點(diǎn)"/a",t2可能是創(chuàng)建節(jié)點(diǎn)"/a/bb",只有先創(chuàng)建了父節(jié)點(diǎn)"/a",才能創(chuàng)建子節(jié)點(diǎn)"/a/b"。

為了保證這一點(diǎn),Zab要保證同一個(gè)Leader發(fā)起的事務(wù)要按順序被Apply,同時(shí)還要保證只有先前Leader的事務(wù)被apply之后,新選舉出來的Leader才能再次發(fā)起事務(wù)。

  1. 當(dāng)主進(jìn)程出現(xiàn)異常的時(shí)候,整個(gè)zk集群依舊能正常工作。

Zab協(xié)議原理

Zab協(xié)議要求每個(gè) Leader 都要經(jīng)歷三個(gè)階段:發(fā)現(xiàn),同步,廣播。

  • 發(fā)現(xiàn):要求zookeeper集群必須選舉出一個(gè) Leader 進(jìn)程,同時(shí) Leader 會(huì)維護(hù)一個(gè) Follower 可用客戶端列表。將來客戶端可以和這些 Follower節(jié)點(diǎn)進(jìn)行通信。
  • 同步:Leader 要負(fù)責(zé)將本身的數(shù)據(jù)與 Follower 完成同步,做到多副本存儲(chǔ)。這樣也是體現(xiàn)了CAP中的高可用和分區(qū)容錯(cuò)。Follower將隊(duì)列中未處理完的請求消費(fèi)完成后,寫入本地事務(wù)日志中。
  • 廣播:Leader 可以接收客戶端新的事務(wù)Proposal請求,將新的Proposal請求廣播給所有的 Follower。

Zab協(xié)議核心

Zab協(xié)議的核心:定義了事務(wù)請求的處理方式

  1. 所有的事務(wù)請求必須由一個(gè)全局唯一的服務(wù)器來協(xié)調(diào)處理,這樣的服務(wù)器被叫做 Leader服務(wù)器。其他剩余的服務(wù)器則是 Follower服務(wù)器
  2. Leader服務(wù)器 負(fù)責(zé)將一個(gè)客戶端事務(wù)請求,轉(zhuǎn)換成一個(gè) 事務(wù)Proposal,并將該 Proposal 分發(fā)給集群中所有的 Follower 服務(wù)器,也就是向所有 Follower 節(jié)點(diǎn)發(fā)送數(shù)據(jù)廣播請求(或數(shù)據(jù)復(fù)制)
  3. 分發(fā)之后Leader服務(wù)器需要等待所有Follower服務(wù)器的反饋(Ack請求),在Zab協(xié)議中,只要超過半數(shù)的Follower服務(wù)器進(jìn)行了正確的反饋后(也就是收到半數(shù)以上的Follower的Ack請求),那么 Leader 就會(huì)再次向所有的 Follower服務(wù)器發(fā)送 Commit 消息,要求其將上一個(gè) 事務(wù)proposal 進(jìn)行提交。
Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

Zab協(xié)議內(nèi)容

Zab 協(xié)議包括兩種基本的模式:崩潰恢復(fù) 和 消息廣播

協(xié)議過程

當(dāng)整個(gè)集群啟動(dòng)過程中,或者當(dāng) Leader 服務(wù)器出現(xiàn)網(wǎng)絡(luò)中弄斷、崩潰退出或重啟等異常時(shí),Zab協(xié)議就會(huì) 進(jìn)入崩潰恢復(fù)模式,選舉產(chǎn)生新的Leader。

當(dāng)選舉產(chǎn)生了新的 Leader,同時(shí)集群中有過半的機(jī)器與該 Leader 服務(wù)器完成了狀態(tài)同步(即數(shù)據(jù)同步)之后,Zab協(xié)議就會(huì)退出崩潰恢復(fù)模式,進(jìn)入消息廣播模式

這時(shí),如果有一臺(tái)遵守Zab協(xié)議的服務(wù)器加入集群,因?yàn)榇藭r(shí)集群中已經(jīng)存在一個(gè)Leader服務(wù)器在廣播消息,那么該新加入的服務(wù)器自動(dòng)進(jìn)入恢復(fù)模式:找到Leader服務(wù)器,并且完成數(shù)據(jù)同步。同步完成后,作為新的Follower一起參與到消息廣播流程中。

協(xié)議狀態(tài)切換

當(dāng)Leader出現(xiàn)崩潰退出或者機(jī)器重啟,亦或是集群中不存在超過半數(shù)的服務(wù)器與Leader保存正常通信,Zab就會(huì)再一次進(jìn)入崩潰恢復(fù),發(fā)起新一輪Leader選舉并實(shí)現(xiàn)數(shù)據(jù)同步。同步完成后又會(huì)進(jìn)入消息廣播模式,接收事務(wù)請求。

保證消息有序

在整個(gè)消息廣播中,Leader會(huì)將每一個(gè)事務(wù)請求轉(zhuǎn)換成對應(yīng)的 proposal 來進(jìn)行廣播,并且在廣播 事務(wù)Proposal 之前,Leader服務(wù)器會(huì)首先為這個(gè)事務(wù)Proposal分配一個(gè)全局單遞增的唯一ID,稱之為事務(wù)ID(即zxid),由于Zab協(xié)議需要保證每一個(gè)消息的嚴(yán)格的順序關(guān)系,因此必須將每一個(gè)proposal按照其zxid的先后順序進(jìn)行排序和處理。

消息廣播

  1. 在zookeeper集群中,數(shù)據(jù)副本的傳遞策略就是采用消息廣播模式。zookeeper中數(shù)據(jù)副本的同步方式與二段提交相似,但是卻又不同。二段提交要求協(xié)調(diào)者必須等到所有的參與者全部反饋ACK確認(rèn)消息后,再發(fā)送commit消息。要求所有的參與者要么全部成功,要么全部失敗。二段提交會(huì)產(chǎn)生嚴(yán)重的阻塞問題。
  2. Zab協(xié)議中 Leader 等待 Follower 的ACK反饋消息是指“只要半數(shù)以上的Follower成功反饋即可,不需要收到全部Follower反饋”
Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

消息廣播具體步驟

  1. 客戶端發(fā)起一個(gè)寫操作請求。
  2. Leader 服務(wù)器將客戶端的請求轉(zhuǎn)化為事務(wù) Proposal 提案,同時(shí)為每個(gè) Proposal 分配一個(gè)全局的ID,即zxid。
  3. Leader 服務(wù)器為每個(gè) Follower 服務(wù)器分配一個(gè)單獨(dú)的隊(duì)列,然后將需要廣播的 Proposal 依次放到隊(duì)列中去,并且根據(jù) FIFO 策略進(jìn)行消息發(fā)送。
  4. Follower 接收到 Proposal 后,會(huì)首先將其以事務(wù)日志的方式寫入本地磁盤中,寫入成功后向 Leader 反饋一個(gè) Ack 響應(yīng)消息。
  5. Leader 接收到超過半數(shù)以上 Follower 的 Ack 響應(yīng)消息后,即認(rèn)為消息發(fā)送成功,可以發(fā)送 commit 消息。
  6. Leader 向所有 Follower 廣播 commit 消息,同時(shí)自身也會(huì)完成事務(wù)提交。Follower 接收到 commit 消息后,會(huì)將上一條事務(wù)提交。

zookeeper 采用 Zab 協(xié)議的核心,就是只要有一臺(tái)服務(wù)器提交了 Proposal,就要確保所有的服務(wù)器最終都能正確提交 Proposal。這也是 CAP/BASE 實(shí)現(xiàn)最終一致性的一個(gè)體現(xiàn)。

Leader 服務(wù)器與每一個(gè) Follower 服務(wù)器之間都維護(hù)了一個(gè)單獨(dú)的 FIFO 消息隊(duì)列進(jìn)行收發(fā)消息,使用隊(duì)列消息可以做到異步解耦。 Leader 和 Follower 之間只需要往隊(duì)列中發(fā)消息即可。如果使用同步的方式會(huì)引起阻塞,性能要下降很多。

崩潰恢復(fù)

一旦 Leader 服務(wù)器出現(xiàn)崩潰或者由于網(wǎng)絡(luò)原因?qū)е?Leader 服務(wù)器失去了與過半 Follower 的聯(lián)系,那么就會(huì)進(jìn)入崩潰恢復(fù)模式。

在 Zab 協(xié)議中,為了保證程序的正確運(yùn)行,整個(gè)恢復(fù)過程結(jié)束后需要選舉出一個(gè)新的 Leader 服務(wù)器。因此 Zab 協(xié)議需要一個(gè)高效且可靠的 Leader 選舉算法,從而確保能夠快速選舉出新的 Leader 。

Leader 選舉算法不僅僅需要讓 Leader 自己知道自己已經(jīng)被選舉為 Leader ,同時(shí)還需要讓集群中的所有其他機(jī)器也能夠快速感知到選舉產(chǎn)生的新 Leader 服務(wù)器。

崩潰恢復(fù)主要包括兩部分:Leader選舉 和 數(shù)據(jù)恢復(fù)

Zab 協(xié)議如何保證數(shù)據(jù)一致性

假設(shè)兩種異常情況:

  1. 一個(gè)事務(wù)在 Leader 上提交了,并且過半的 Folower 都響應(yīng) Ack 了,但是 Leader 在 Commit 消息發(fā)出之前掛了。
  2. 假設(shè)一個(gè)事務(wù)在 Leader 提出之后,Leader 掛了。

要確保如果發(fā)生上述兩種情況,數(shù)據(jù)還能保持一致性,那么 Zab 協(xié)議選舉算法必須滿足以下要求:

Zab 協(xié)議崩潰恢復(fù)要求滿足以下兩個(gè)要求

  1. 確保已經(jīng)被 Leader 提交的 Proposal 必須最終被所有的 Follower 服務(wù)器提交。
  2. 確保丟棄已經(jīng)被 Leader 提出的但是沒有被提交的 Proposal。

根據(jù)上述要求 Zab協(xié)議需要保證選舉出來的Leader需要滿足以下條件:

  1. 新選舉出來的 Leader 不能包含未提交的 Proposal 。

即新選舉的 Leader 必須都是已經(jīng)提交了 Proposal 的 Follower 服務(wù)器節(jié)點(diǎn)。

  1. 新選舉的 Leader 節(jié)點(diǎn)中含有最大的 zxid 。

這樣做的好處是可以避免 Leader 服務(wù)器檢查 Proposal 的提交和丟棄工作。

Zab 如何數(shù)據(jù)同步

  1. 完成 Leader 選舉后(新的 Leader 具有最高的zxid),在正式開始工作之前(接收事務(wù)請求,然后提出新的 Proposal),Leader 服務(wù)器會(huì)首先確認(rèn)事務(wù)日志中的所有的 Proposal 是否已經(jīng)被集群中過半的服務(wù)器 Commit。
  2. Leader 服務(wù)器需要確保所有的 Follower 服務(wù)器能夠接收到每一條事務(wù)的 Proposal ,并且能將所有已經(jīng)提交的事務(wù) Proposal 應(yīng)用到內(nèi)存數(shù)據(jù)中。等到 Follower 將所有尚未同步的事務(wù) Proposal 都從 Leader 服務(wù)器上同步過啦并且應(yīng)用到內(nèi)存數(shù)據(jù)中以后,Leader 才會(huì)把該 Follower 加入到真正可用的 Follower 列表中。

Zab 數(shù)據(jù)同步過程中,如何處理需要丟棄的 Proposal

在 Zab 的事務(wù)編號 zxid 設(shè)計(jì)中,zxid是一個(gè)64位的數(shù)字。

其中低32位可以看成一個(gè)簡單的單增計(jì)數(shù)器,針對客戶端每一個(gè)事務(wù)請求,Leader 在產(chǎn)生新的 Proposal 事務(wù)時(shí),都會(huì)對該計(jì)數(shù)器加1。而高32位則代表了 Leader 周期的 epoch 編號。

epoch 編號可以理解為當(dāng)前集群所處的年代,或者周期。每次Leader變更之后都會(huì)在 epoch 的基礎(chǔ)上加1,這樣舊的 Leader 崩潰恢復(fù)之后,其他Follower 也不會(huì)聽它的了,因?yàn)?Follower 只服從epoch最高的 Leader 命令。

每當(dāng)選舉產(chǎn)生一個(gè)新的 Leader ,就會(huì)從這個(gè) Leader 服務(wù)器上取出本地事務(wù)日志最大編號 Proposal 的 zxid,并從 zxid 中解析得到對應(yīng)的 epoch 編號,然后再對其加1,之后該編號就作為新的 epoch 值,并將低32位數(shù)字歸零,由0開始重新生成zxid。

Zab 協(xié)議通過 epoch 編號來區(qū)分 Leader 變化周期,能夠有效避免不同的 Leader 錯(cuò)誤的使用了相同的 zxid 編號提出了不一樣的 Proposal 的異常情況。

基于以上策略: 當(dāng)一個(gè)包含了上一個(gè) Leader 周期中尚未提交過的事務(wù) Proposal 的服務(wù)器啟動(dòng)時(shí),當(dāng)這臺(tái)機(jī)器加入集群中,以 Follower 角色連上 Leader 服務(wù)器后,Leader 服務(wù)器會(huì)根據(jù)自己服務(wù)器上最后提交的 Proposal 來和 Follower 服務(wù)器的 Proposal 進(jìn)行比對,比對的結(jié)果肯定是 Leader 要求 Follower 進(jìn)行一個(gè)回退操作,回退到一個(gè)確實(shí)已經(jīng)被集群中過半機(jī)器 Commit 的最新 Proposal。

Zab實(shí)現(xiàn)原理

Zab 節(jié)點(diǎn)有三種狀態(tài)

  • Following:當(dāng)前節(jié)點(diǎn)是跟隨者,服從 Leader 節(jié)點(diǎn)的命令。
  • Leading:當(dāng)前節(jié)點(diǎn)是 Leader,負(fù)責(zé)協(xié)調(diào)事務(wù)。
  • Election/Looking:節(jié)點(diǎn)處于選舉狀態(tài),正在尋找 Leader。

代碼實(shí)現(xiàn)中,多了一種狀態(tài):Observing 狀態(tài) 這是 Zookeeper 引入 Observer 之后加入的,Observer 不參與選舉,是只讀節(jié)點(diǎn),跟 Zab 協(xié)議沒有關(guān)系。

節(jié)點(diǎn)的持久狀態(tài)

  • history:當(dāng)前節(jié)點(diǎn)接收到事務(wù) Proposal 的Log
  • acceptedEpoch:Follower 已經(jīng)接收的 Leader 更改 epoch 的 newEpoch 提議。
  • currentEpoch:當(dāng)前所處的 Leader 年代
  • lastZxid:history 中最近接收到的Proposal 的 zxid(最大zxid)

Zab 的四個(gè)階段

  1. 選舉階段(Leader Election)

節(jié)點(diǎn)在一開始都處于選舉節(jié)點(diǎn),只要有一個(gè)節(jié)點(diǎn)得到超過半數(shù)節(jié)點(diǎn)的票數(shù),它就可以當(dāng)選準(zhǔn) Leader,只有到達(dá)第三個(gè)階段(也就是同步階段),這個(gè)準(zhǔn) Leader 才會(huì)成為真正的 Leader。

Zookeeper 規(guī)定所有有效的投票都必須在同一個(gè) 輪次 中,每個(gè)服務(wù)器在開始新一輪投票時(shí),都會(huì)對自己維護(hù)的 logicalClock 進(jìn)行自增操作。

每個(gè)服務(wù)器在廣播自己的選票前,會(huì)將自己的投票箱(recvset)清空。該投票箱記錄了所收到的選票。

例如:Server_2 投票給 Server_3,Server_3 投票給 Server_1,則Server_1的投票箱為(2,3)、(3,1)、(1,1)。(每個(gè)服務(wù)器都會(huì)默認(rèn)給自己投票)

前一個(gè)數(shù)字表示投票者,后一個(gè)數(shù)字表示被選舉者。票箱中只會(huì)記錄每一個(gè)投票者的最后一次投票記錄,如果投票者更新自己的選票,則其他服務(wù)器收到該新選票后會(huì)在自己的票箱中更新該服務(wù)器的選票。

這一階段的目的就是為了選出一個(gè)準(zhǔn) Leader ,然后進(jìn)入下一個(gè)階段。

協(xié)議并沒有規(guī)定詳細(xì)的選舉算法,后面會(huì)提到實(shí)現(xiàn)中使用的 Fast Leader Election。

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

  1. 發(fā)現(xiàn)階段(Descovery)

在這個(gè)階段,F(xiàn)ollowers 和上一輪選舉出的準(zhǔn) Leader 進(jìn)行通信,同步 Followers 最近接收的事務(wù) Proposal 。

一個(gè) Follower 只會(huì)連接一個(gè) Leader,如果一個(gè) Follower 節(jié)點(diǎn)認(rèn)為另一個(gè) Follower 節(jié)點(diǎn),則會(huì)在嘗試連接時(shí)被拒絕。被拒絕之后,該節(jié)點(diǎn)就會(huì)進(jìn)入 Leader Election階段。

這個(gè)階段的主要目的是發(fā)現(xiàn)當(dāng)前大多數(shù)節(jié)點(diǎn)接收的最新 Proposal,并且準(zhǔn) Leader 生成新的 epoch ,讓 Followers 接收,更新它們的 acceptedEpoch

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

  1. 同步階段(Synchronization)

同步階段主要是利用 Leader 前一階段獲得的最新 Proposal 歷史,同步集群中所有的副本。

只有當(dāng) quorum(超過半數(shù)的節(jié)點(diǎn)) 都同步完成,準(zhǔn) Leader 才會(huì)成為真正的 Leader。Follower 只會(huì)接受 zxid 比自己 lastZxid 大的 Proposal。

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

  1. 廣播階段(Broadcast)

到了這個(gè)階段,Zookeeper 集群才能正式對外提供事務(wù)服務(wù),并且 Leader 可以進(jìn)行消息廣播。同時(shí),如果有新的節(jié)點(diǎn)加入,還需要對新節(jié)點(diǎn)進(jìn)行同步。

需要注意的是,Zab 提交事務(wù)并不像 2PC 一樣需要全部 Follower 都 Ack,只需要得到 quorum(超過半數(shù)的節(jié)點(diǎn))的Ack 就可以。

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

Zab協(xié)議實(shí)現(xiàn)

協(xié)議的 Java 版本實(shí)現(xiàn)跟上面的定義略有不同,選舉階段使用的是 Fast Leader Election(FLE),它包含了步驟1的發(fā)現(xiàn)職責(zé)。因?yàn)镕LE會(huì)選舉擁有最新提議的歷史節(jié)點(diǎn)作為 Leader,這樣就省去了發(fā)現(xiàn)最新提議的步驟。

實(shí)際的實(shí)現(xiàn)將發(fā)現(xiàn)和同步階段合并為 Recovery Phase(恢復(fù)階段),所以,Zab 的實(shí)現(xiàn)實(shí)際上有三個(gè)階段。

Zab協(xié)議三個(gè)階段:

  1. 選舉(Fast Leader Election)
  2. 恢復(fù)(Recovery Phase)
  3. 廣播(Broadcast Phase)

Fast Leader Election(快速選舉)

前面提到的 FLE 會(huì)選舉擁有最新Proposal history (lastZxid最大)的節(jié)點(diǎn)作為 Leader,這樣就省去了發(fā)現(xiàn)最新提議的步驟。這是基于擁有最新提議的節(jié)點(diǎn)也擁有最新的提交記錄

成為 Leader 的條件:

  1. 選 epoch 最大的
  2. 若 epoch 相等,選 zxid 最大的
  3. 若 epoch 和 zxid 相等,選擇 server_id 最大的(zoo.cfg中的myid)

節(jié)點(diǎn)在選舉開始時(shí),都默認(rèn)投票給自己,當(dāng)接收其他節(jié)點(diǎn)的選票時(shí),會(huì)根據(jù)上面的 Leader條件 判斷并且更改自己的選票,然后重新發(fā)送選票給其他節(jié)點(diǎn)。當(dāng)有一個(gè)節(jié)點(diǎn)的得票超過半數(shù),該節(jié)點(diǎn)會(huì)設(shè)置自己的狀態(tài)為 Leading ,其他節(jié)點(diǎn)會(huì)設(shè)置自己的狀態(tài)為 Following。

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

Recovery Phase(恢復(fù)階段)

這一階段 Follower 發(fā)送他們的 lastZxid 給 Leader,Leader 根據(jù) lastZxid 決定如何同步數(shù)據(jù)。這里的實(shí)現(xiàn)跟前面的 Phase 2 有所不同:Follower 收到 TRUNC 指令會(huì)終止 L.lastCommitedZxid 之后的 Proposal ,收到 DIFF 指令會(huì)接收新的 Proposal。

history.lastCommitedZxid:最近被提交的 Proposal zxid history.oldThreshold:被認(rèn)為已經(jīng)太舊的已經(jīng)提交的 Proposal zxid

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼

啟動(dòng)流程

知識(shí)點(diǎn):

  1. 工程結(jié)構(gòu)介紹
  2. 啟動(dòng)流程宏觀圖
  3. 集群啟動(dòng)詳細(xì)流程
  4. netty 服務(wù)工作機(jī)制

工程結(jié)構(gòu)介紹

項(xiàng)目地址:https://github.com/Apache/zookeeper.git

分支tag :3.6.2

  • zookeeper-recipes: 示例源碼
  • zookeeper-client: C語言客戶端
  • zookeeper-server:主體源碼(包含客戶端)

啟動(dòng)宏觀流程圖

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

源碼啟動(dòng):

  • 服務(wù)端:ZooKeeperServerMain
  • 客戶端:ZooKeeperMain

為方便閱讀,以下代碼均省略包名

集群啟動(dòng)詳細(xì)流程

裝載配置

# zookeeper 啟動(dòng)流程堆棧
 >QuorumPeerMain#initializeAndRun //啟動(dòng)工程 
   >QuorumPeerConfig#parse // 加載config 配置
    >QuorumPeerConfig#parseProperties// 解析config配置
 >new DatadirCleanupManager // 構(gòu)造一個(gè)數(shù)據(jù)清器
  >DatadirCleanupManager#start // 啟動(dòng)定時(shí)任務(wù) 清除過期的快照

代碼堆棧

>QuorumPeerMain#main  //啟動(dòng)main方法
 >QuorumPeerConfig#parse // 加載zoo.cfg 文件
   >QuorumPeerConfig#parseProperties // 解析配置
 >DatadirCleanupManager#start // 啟動(dòng)定時(shí)任務(wù)清除日志
 >QuorumPeerConfig#isDistributed // 判斷是否為集群模式
  >ServerCnxnFactory#createFactory() // 創(chuàng)建服務(wù)默認(rèn)為NIO,推薦netty
 //***創(chuàng)建 初始化集群管理器**/
 >QuorumPeerMain#getQuorumPeer
 >QuorumPeer#setTxnFactory 
 >new FileTxnSnapLog // 數(shù)據(jù)文件管理器,用于檢測快照與日志文件
   /**  初始化數(shù)據(jù)庫*/
  >new ZKDatabase 
    >ZKDatabase#createDataTree //創(chuàng)建數(shù)據(jù)樹,所有的節(jié)點(diǎn)都會(huì)存儲(chǔ)在這
 // 啟動(dòng)集群:同時(shí)啟動(dòng)線程
  > QuorumPeer#start // 
    > QuorumPeer#loadDataBase // 從快照文件以及日志文件 加載節(jié)點(diǎn)并填充到dataTree中去
    > QuorumPeer#startServerCnxnFactory // 啟動(dòng)netty 或java nio 服務(wù),對外開放2181 端口
    > AdminServer#start// 啟動(dòng)管理服務(wù),netty http服務(wù),默認(rèn)端口是8080
    > QuorumPeer#startLeaderElection // 開始執(zhí)行選舉流程
    > quorumPeer.join()  // 防止主進(jìn)程退出

流程說明:

  1. main方法啟動(dòng)
  2. 加載zoo.cfg 配置文件
  3. 解析配置
  4. 創(chuàng)建服務(wù)工廠
  5. 創(chuàng)建集群管理線程
  6. 設(shè)置數(shù)據(jù)庫文件管理器
  7. 設(shè)置數(shù)據(jù)庫
  8. ....設(shè)置設(shè)置
  9. start啟動(dòng)集群管理線程
  10. 加載數(shù)據(jù)節(jié)點(diǎn)至內(nèi)存
  11. 啟動(dòng)netty 服務(wù),對客戶端開放端口
  12. 啟動(dòng)管理員Http服務(wù),默認(rèn)8080端口
  13. 啟動(dòng)選舉流程
  14. join 管理線程,防止main 進(jìn)程退出

netty 服務(wù)啟動(dòng)流程

服務(wù)UML類圖

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

設(shè)置netty啟動(dòng)參數(shù)

-Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory

初始化:

關(guān)鍵代碼:

#初始化管道流 
#channelHandler 是一個(gè)內(nèi)部類是具體的消息處理器。protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();    if (secure) {
        initSSL(pipeline);    }    pipeline.addLast("servercnxnfactory", channelHandler);
}

channelHandler 類結(jié)構(gòu)

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

執(zhí)行堆棧:

NettyServerCnxnFactory#NettyServerCnxnFactory  // 初始化netty服務(wù)工廠
  > NettyUtils.newNioOrEpollEventLoopGroup  // 創(chuàng)建IO線程組
  > NettyUtils#newNioOrEpollEventLoopGroup()  // 創(chuàng)建工作線程組
  >ServerBootstrap#childHandler(io.netty.channel.ChannelHandler) // 添加管道流
>NettyServerCnxnFactory#start    // 綁定端口,并啟動(dòng)netty服務(wù)

創(chuàng)建連接:

每當(dāng)有客戶端新連接進(jìn)來,就會(huì)進(jìn)入該方法 創(chuàng)建 NettyServerCnxn對象。并添加至cnxns隊(duì)列

執(zhí)行堆棧

CnxnChannelHandler#channelActive
 >new NettyServerCnxn        // 構(gòu)建連接器
>NettyServerCnxnFactory#addCnxn     // 添加至連接器,并根據(jù)客戶端IP進(jìn)行分組
 >ipMap.get(addr) // 基于IP進(jìn)行分組

讀取消息:

執(zhí)行堆棧

CnxnChannelHandler#channelRead
>NettyServerCnxn#processMessage //  處理消息 
 >NettyServerCnxn#receiveMessage // 接收消息
  >ZooKeeperServer#processPacket //處理消息包
   >org.apache.zookeeper.server.Request // 封裝request 對象
    >org.apache.zookeeper.server.ZooKeeperServer#submitRequest // 提交request  
     >org.apache.zookeeper.server.RequestProcessor#processRequest // 處理請求

快照與事務(wù)日志存儲(chǔ)結(jié)構(gòu)

概要

ZK中所有的數(shù)據(jù)都是存儲(chǔ)在內(nèi)存中,即zkDataBase中。但同時(shí)所有對ZK數(shù)據(jù)的變更都會(huì)記錄到事務(wù)日志中,并且當(dāng)寫入到一定的次數(shù)就會(huì)進(jìn)行一次快照的生成。已保證數(shù)據(jù)的備份。其后綴就是ZXID(唯一事務(wù)ID)。

  • 事務(wù)日志:每次增刪改,的記錄日志都會(huì)保存在文件當(dāng)中
  • 快照日志:存儲(chǔ)了在指定時(shí)間節(jié)點(diǎn)下的所有的數(shù)據(jù)

存儲(chǔ)結(jié)構(gòu)

zkDdataBase 是zk數(shù)據(jù)庫基類,所有節(jié)點(diǎn)都會(huì)保存在該類當(dāng)中,而對Zk進(jìn)行任何的數(shù)據(jù)變更都會(huì)基于該類進(jìn)行。zk數(shù)據(jù)的存儲(chǔ)是通過DataTree 對象進(jìn)行,其用了一個(gè)map 來進(jìn)行存儲(chǔ)。

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

UML 類圖:

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

讀取快照日志:

org.apache.zookeeper.server.SnapshotFormatter

讀取事務(wù)日志:

org.apache.zookeeper.server.LogFormatter

快照相關(guān)配置

 

Zookeeper ZAB協(xié)議實(shí)現(xiàn)源碼分析

 

快照裝載流程

>ZooKeeperServer#loadData // 加載數(shù)據(jù)
>FileTxnSnapLog#restore // 恢復(fù)數(shù)據(jù)
>FileSnap#deserialize() // 反序列化數(shù)據(jù)
>FileSnap#findNValidSnapshots // 查找有效的快照
  >Util#sortDataDir // 基于后綴排序文件

分享到:
標(biāo)簽:Zookeeper ZAB
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定