您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)Zookeeper中怎么實現(xiàn)一個Zab協(xié)議,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
Zookeeper是一個分布式數(shù)據(jù)一致性的解決方案,分布式應(yīng)用可以基于它實現(xiàn)諸如數(shù)據(jù)發(fā)布/訂閱,負載均衡,命名服務(wù),分布式協(xié)調(diào)/通知,集群管理,Master選舉,分布式鎖和分布式隊列等功能。Zookeeper致力于提供一個高性能、高可用、且具有嚴格的順序訪問控制能力的分布式協(xié)調(diào)系統(tǒng)。
考慮到Zookeeper主要操作數(shù)據(jù)的狀態(tài),為了保證狀態(tài)的一致性,Zookeeper提出了兩個安全屬性:
全序(Total order):如果消息a在消息b之前發(fā)送,則所有Server應(yīng)該看到相同的結(jié)果;
因果順序(Causal order):如果消息a在消息b之前發(fā)生(a導致了b),并被一起發(fā)送,則a始終在b之前被執(zhí)行;
為了保證上述兩個安全屬性,Zookeeper使用了TCP協(xié)議和Leader:
通過使用TCP協(xié)議保證了消息的全序特性(先發(fā)先到);
通過Leader解決了因果順序問題:先到Leader的先執(zhí)行,但是這樣的話Leader有可能出現(xiàn)出現(xiàn)網(wǎng)絡(luò)中斷、崩潰退出與重啟等異常情況,這就有必要引入Leader選舉算法;
而ZAB(Zookeeper Atomic Broadcast即Zookeeper原子消息廣播協(xié)議)正是作為其數(shù)據(jù)一致性的核心算法,下面介紹一下ZAB協(xié)議。
ZAB ,Zookeeper Atomic Broadcast,zk 原子消息廣播協(xié)議,是專為 ZooKeeper 設(shè)計的一 種支持崩潰恢復的原子廣播協(xié)議。在 Zookeeper 中,基于該協(xié)議,ZooKeeper 實現(xiàn)了一種主從模式的系統(tǒng)架構(gòu)來保持集群中各個副本之間的數(shù)據(jù)一致性。
Zookeeper 使用一個單一主進程來接收并處理客戶端的所有事務(wù)請求,即寫請求。當服 務(wù)器數(shù)據(jù)的狀態(tài)發(fā)生變更后,集群采用 ZAB 原子廣播協(xié)議,以事務(wù)提案 Proposal 的形式廣 播到所有的副本進程上。ZAB 協(xié)議能夠保證一個全局的變更序列,即可以為每一個事務(wù)分配 一個全局的遞增編號 xid。
當 Zookeeper 客戶端連接到 Zookeeper 集群的一個節(jié)點后,若客戶端提交的是讀請求, 那么當前節(jié)點就直接根據(jù)自己保存的數(shù)據(jù)對其進行響應(yīng);如果是寫請求且當前節(jié)點不是 Leader,那么節(jié)點就會將該寫請求轉(zhuǎn)發(fā)給 Leader,Leader 會以提案的方式廣播該寫操作,只 要有超過半數(shù)節(jié)點同意該寫操作,則該寫操作請求就會被提交。然后 Leader 會再次廣播給 所有訂閱者,即 Learner,通知它們同步數(shù)據(jù)。
Zab協(xié)議要求每個 Leader 都要經(jīng)歷三個階段:發(fā)現(xiàn),同步,廣播。
發(fā)現(xiàn):要求zookeeper集群必須選舉出一個 Leader 進程,同時 Leader 會維護一個 Follower 可用客戶端列表。將來客戶端可以和這些 Follower節(jié)點進行通信。
同步:Leader 要負責將本身的數(shù)據(jù)與 Follower 完成同步,做到多副本存儲。這樣也是提現(xiàn)了CAP中的高可用和分區(qū)容錯。Follower將隊列中未處理完的請求消費完成后,寫入本地事務(wù)日志中
廣播:Leader 可以接受客戶端新的事務(wù)Proposal請求,將新的Proposal請求廣播給所有的 Follower。
Zab協(xié)議的核心:定義了事務(wù)請求的處理方式
所有的事務(wù)請求必須由一個全局唯一的服務(wù)器來協(xié)調(diào)處理,這樣的服務(wù)器被叫做 Leader服務(wù)器。其他剩余的服務(wù)器則是 Follower服務(wù)器。
Leader服務(wù)器 負責將一個客戶端事務(wù)請求,轉(zhuǎn)換成一個 事務(wù)Proposal,并將該 Proposal 分發(fā)給集群中所有的 Follower 服務(wù)器,也就是向所有 Follower 節(jié)點發(fā)送數(shù)據(jù)廣播請求(或數(shù)據(jù)復制)
分發(fā)之后Leader服務(wù)器需要等待所有Follower服務(wù)器的反饋(Ack請求),在Zab協(xié)議中,只要超過半數(shù)的Follower服務(wù)器進行了正確的反饋后(也就是收到半數(shù)以上的Follower的Ack請求),那么 Leader 就會再次向所有的 Follower服務(wù)器發(fā)送 Commit 消息,要求其將上一個 事務(wù)proposal 進行提交。
Zab 協(xié)議包括兩種基本的模式:崩潰恢復 和 消息廣播
當整個集群啟動過程中,或者當 Leader 服務(wù)器出現(xiàn)網(wǎng)絡(luò)中弄斷、崩潰退出或重啟等異常時,Zab協(xié)議就會 進入崩潰恢復模式,選舉產(chǎn)生新的Leader。
當選舉產(chǎn)生了新的 Leader,同時集群中有過半的機器與該 Leader 服務(wù)器完成了狀態(tài)同步(即數(shù)據(jù)同步)之后,Zab協(xié)議就會退出崩潰恢復模式,進入消息廣播模式。
這時,如果有一臺遵守Zab協(xié)議的服務(wù)器加入集群,因為此時集群中已經(jīng)存在一個Leader服務(wù)器在廣播消息,那么該新加入的服務(wù)器自動進入恢復模式:找到Leader服務(wù)器,并且完成數(shù)據(jù)同步。同步完成后,作為新的Follower一起參與到消息廣播流程中。
當Leader出現(xiàn)崩潰退出或者機器重啟,亦或是集群中不存在超過半數(shù)的服務(wù)器與Leader保存正常通信,Zab就會再一次進入崩潰恢復,發(fā)起新一輪Leader選舉并實現(xiàn)數(shù)據(jù)同步。同步完成后又會進入消息廣播模式,接收事務(wù)請求。
在整個消息廣播中,Leader會將每一個事務(wù)請求轉(zhuǎn)換成對應(yīng)的 proposal 來進行廣播,并且在廣播 事務(wù)Proposal 之前,Leader服務(wù)器會首先為這個事務(wù)Proposal分配一個全局單遞增的唯一ID,稱之為事務(wù)ID(即zxid),由于Zab協(xié)議需要保證每一個消息的嚴格的順序關(guān)系,因此必須將每一個proposal按照其zxid的先后順序進行排序和處理。
一旦 Leader 服務(wù)器出現(xiàn)崩潰或者由于網(wǎng)絡(luò)原因?qū)е?Leader 服務(wù)器失去了與過半 Follower 的聯(lián)系,那么就會進入崩潰恢復模式。
前面我們說過,崩潰恢復具有兩個階段:Leader 選舉與初始化同步。當完成 Leader 選 舉后,此時的 Leader 還是一個準 Leader,其要經(jīng)過初始化同步后才能變?yōu)檎嬲?Leader。
具體過程如下:
為了保證 Leader 向 Learner 發(fā)送提案的有序,Leader 會為每一個 Learner 服務(wù)器準備一 個隊列;
Leader 將那些沒有被各個 Learner 同步的事務(wù)封裝為 Proposal;
Leader 將這些 Proposal 逐條發(fā)給各個 Learner,并在每一個 Proposal 后都緊跟一個 COMMIT 消息,表示該事務(wù)已經(jīng)被提交,Learner 可以直接接收并執(zhí)行 ;
Learner 接收來自于 Leader 的 Proposal,并將其更新到本地;
當 Learner 更新成功后,會向準 Leader 發(fā)送 ACK 信息;
Leader 服務(wù)器在收到來自 Learner 的 ACK 后就會將該 Learner 加入到真正可用的 Follower 列表或 Observer 列表。沒有反饋 ACK,或反饋了但 Leader 沒有收到的 Learner,Leader 不會將其加入到相應(yīng)列表。
當集群正在啟動過程中,或 Leader 與超過半數(shù)的主機斷連后,集群就進入了恢復模式。 對于要恢復的數(shù)據(jù)狀態(tài)需要遵循兩個原則。
當 Leader 收到超過半數(shù) Follower 的 ACKs 后,就向各個 Follower 廣播 COMMIT 消息, 批準各個 Server 執(zhí)行該寫操作事務(wù)。當各個 Server 在接收到 Leader 的 COMMIT 消息后就會在本地執(zhí)行該寫操作,然后會向客戶端響應(yīng)寫操作成功。
但是如果在非全部 Follower 收到 COMMIT 消息之前 Leader 就掛了,這將導致一種后 果:部分 Server 已經(jīng)執(zhí)行了該事務(wù),而部分 Server 尚未收到 COMMIT 消息,所以其并沒有 執(zhí)行該事務(wù)。當新的 Leader 被選舉出,集群經(jīng)過恢復模式后需要保證所有 Server 上都執(zhí)行 了那些已經(jīng)被部分 Server 執(zhí)行過的事務(wù)。
當在 Leader 新事務(wù)已經(jīng)通過,其已經(jīng)將該事務(wù)更新到了本地,但所有 Follower 還都沒 有收到 COMMIT 之前,Leader 宕機了(比前面敘述的宕機更早),此時,所有 Follower 根本 就不知道該 Proposal 的存在。當新的 Leader 選舉出來,整個集群進入正常服務(wù)狀態(tài)后,之 前掛了的 Leader 主機重新啟動并注冊成為了 Follower。若那個別人根本不知道的 Proposal 還保留在那個主機,那么其數(shù)據(jù)就會比其它主機多出了內(nèi)容,導致整個系統(tǒng)狀態(tài)的不一致。 所以,該 Proposa 應(yīng)該被丟棄。類似這樣應(yīng)該被丟棄的事務(wù),是不能再次出現(xiàn)在集群中的, 應(yīng)該被清除。
當集群中的 Learner 完成了初始化狀態(tài)同步,那么整個 zk 集群就進入到了正常工作模式 了。
如果集群中的 Learner 節(jié)點收到客戶端的事務(wù)請求,那么這些 Learner 會將請求轉(zhuǎn)發(fā)給 Leader 服務(wù)器。然后再執(zhí)行如下的具體過程:
Leader 接收到事務(wù)請求后,為事務(wù)賦予一個全局唯一的 64 位自增 id,即 zxid,通過 zxid 的大小比較即可實現(xiàn)事務(wù)的有序性管理,然后將事務(wù)封裝為一個 Proposal。
Leader 根據(jù) Follower 列表獲取到所有 Follower,然后再將 Proposal 通過這些 Follower 的 隊列將提案發(fā)送給各個 Follower。
當 Follower 接收到提案后,會先將提案的 zxid 與本地記錄的事務(wù)日志中的最大的 zxid 進行比較。若當前提案的 zxid 大于最大 zxid,則將當前提案記錄到本地事務(wù)日志中,并 向 Leader 返回一個 ACK。(提問學員)
當 Leader 接收到過半的 ACKs 后,Leader 就會向所有 Follower 的隊列發(fā)送 COMMIT 消息,向所有 Observer 的隊列發(fā)送 Proposal。
當 Follower 收到 COMMIT 消息后,就會將日志中的事務(wù)正式更新到本地。當 Observer 收到 Proposal 后,會直接將事務(wù)更新到本地。
無論是 Follower 還是 Observer,在同步完成后都需要向 Leader 發(fā)送成功 ACK。
為了避免 Zookeeper 的單點問題,zk 也是以集群的形式出現(xiàn)的。zk 集群中的角色主要有 以下三類:
Leader:接收和處理客戶端的讀請求;zk 集群中事務(wù)請求的唯一處理者,并負責發(fā)起決 議和投票,然后將通過的事務(wù)請求在本地進行處理后,將處理結(jié)果同步給集群中的其它主機。
Follower:接收和處理客戶端的讀請求; 將事務(wù)請求轉(zhuǎn)給 Leader;同步 Leader 中的數(shù)據(jù); 當 Leader 掛了,參與 Leader 的選舉(具有選舉權(quán)與被選舉權(quán));
Observer:就是沒有選舉權(quán)與被選舉權(quán),且沒有投票權(quán)的 Follower(臨時工)。若 zk 集 群中的讀壓力很大,則需要增加 Observer,最好不要增加 Follower。因為增加 Follower 將會增大投票與統(tǒng)計選票的壓力,降低寫操作效率,及 Leader 選舉的效率。
這三類角色在不同的情況下又有一些不同的名稱(這個為了下一篇閱讀源碼做準備,可以先了解即可):
Learner = Follower + Observer
QuorumServer = Follower + Leader
在 ZAB 中有三個很重要的數(shù)據(jù):
zxid:是一個 64 位長度的 Long 類型。其中高 32 位表示 epoch,低 32 表示 xid。
epoch:每個 Leader 都會具有一個不同的 epoch,用于區(qū)分不同的時期(可以理解為朝代的年號)
xid:事務(wù) id,是一個流水號,(每次朝代更替,即leader更換),從0開始遞增。
每當選舉產(chǎn)生一個新的 Leader ,就會從這個 Leader 服務(wù)器上取出本地事務(wù)日志中最大編號 Proposal 的 zxid,并從 zxid 中解析得到對應(yīng)的 epoch 編號,然后再對其加1,之后該編號就作為新的 epoch 值,并將低32位數(shù)字歸零,由0開始重新生成zxid。
zk 集群中的每一臺主機,在不同的階段會處于不同的狀態(tài)。每一臺主機具有四種狀態(tài)。
LOOKING:選舉狀態(tài)
FOLLOWING:Follower 的正常工作狀態(tài),從 Leader 同步數(shù)據(jù)的狀態(tài)
LEADING:Leader 的正常工作狀態(tài),Leader 廣播數(shù)據(jù)更新的狀態(tài)
OBSERVING:Observer 的正常工作狀態(tài),從 Leader 同步數(shù)據(jù)的狀態(tài)
代碼實現(xiàn)中,多了一種狀態(tài):Observing 狀態(tài)這是 Zookeeper 引入 Observer 之后加入的,Observer 不參與選舉,是只讀節(jié)點,實際上跟 Zab 協(xié)議沒有關(guān)系。這里為了閱讀源碼加上此概念。
myid:這是 zk 集群中服務(wù)器的唯一標識,稱為 myid。例如,有三個 zk 服務(wù)器,那么編號分別 是 1,2,3。
邏輯時鐘:邏輯時鐘,Logicalclock,是一個整型數(shù),該概念在選舉時稱為 logicalclock,而在選舉結(jié) 束后稱為 epoch。即 epoch 與 logicalclock 是同一個值,在不同情況下的不同名稱。
節(jié)點在一開始都處于選舉節(jié)點,只要有一個節(jié)點得到超過半數(shù)節(jié)點的票數(shù),它就可以當選準 Leader,只有到達第三個階段(也就是同步階段),這個準 Leader 才會成為真正的 Leader。
Zookeeper 規(guī)定所有有效的投票都必須在同一個 輪次 中,每個服務(wù)器在開始新一輪投票時,都會對自己維護的 logicalClock 進行自增操作。
每個服務(wù)器在廣播自己的選票前,會將自己的投票箱(recvset)清空。該投票箱記錄了所受到的選票。
例如:Server_2 投票給 Server_3,Server_3 投票給 Server_1,則Server_1的投票箱為(2,3)、(3,1)、(1,1)。(每個服務(wù)器都會默認給自己投票)
前一個數(shù)字表示投票者,后一個數(shù)字表示被選舉者。票箱中只會記錄每一個投票者的最后一次投票記錄,如果投票者更新自己的選票,則其他服務(wù)器收到該新選票后會在自己的票箱中更新該服務(wù)器的選票。**思考下:這里在實現(xiàn)中應(yīng)該怎么實現(xiàn)呢?**等我們分析源碼時就可以看到,非常的巧妙。
這一階段的目的就是為了選出一個準 Leader ,然后進入下一個階段。
在這個階段,F(xiàn)ollowers 和上一輪選舉出的準 Leader 進行通信,同步 Followers 最近接收的事務(wù) Proposal 。
這個階段的主要目的是發(fā)現(xiàn)當前大多數(shù)節(jié)點接收的最新 Proposal,并且準 Leader 生成新的 epoch ,讓 Followers 接收,更新它們的 acceptedEpoch。
同步階段主要是利用 Leader 前一階段獲得的最新 Proposal 歷史,同步集群中所有的副本。
只有當 quorum(超過半數(shù)的節(jié)點) 都同步完成,準 Leader 才會成為真正的 Leader。Follower 只會接收 zxid 比自己 lastZxid 大的 Proposal。
到了這個階段,Zookeeper 集群才能正式對外提供事務(wù)服務(wù),并且 Leader 可以進行消息廣播。同時,如果有新的節(jié)點加入,還需要對新節(jié)點進行同步。 需要注意的是,Zab 提交事務(wù)并不像 2PC 一樣需要全部 Follower 都 Ack,只需要得到 quorum(超過半數(shù)的節(jié)點)的Ack 就可以。
上面已經(jīng)針對Zab協(xié)議涉及流程作了詳細的描述,那么它和Paxos是什么關(guān)系呢?
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算法的確是不關(guān)心請求之間的邏輯順序,而只考慮數(shù)據(jù)之間的全序,但很少有人直接使用paxos算法,都會經(jīng)過一定的簡化、優(yōu)化。
Google的粗粒度鎖服務(wù)Chubby的設(shè)計開發(fā)者Burrows曾經(jīng)說過:“所有一致性協(xié)議本質(zhì)上要么是Paxos要么是其變體”。這句話還是有一定道理的,ZAB本質(zhì)上就是Paxos的一種簡化形式。
關(guān)于Zookeeper中怎么實現(xiàn)一個Zab協(xié)議就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。