1. 開卷有益
學(xué)習(xí)是一種習(xí)慣,只有把這種習(xí)慣保持下來,每天不學(xué)習(xí)一點(diǎn)就感覺渾身不自在,達(dá)到這樣的境界,那么你成為大佬也就不遠(yuǎn)了買,正如我們標(biāo)題所寫的“開卷有益”。人生匆匆,要想過得有意義,那么加油吧!
文章很長(zhǎng),先贊后看,養(yǎng)成習(xí)慣。
2. 什么是ZooKeeper
ZooKeeper 由 Yahoo 開發(fā),后來捐贈(zèng)給了 Apache ,現(xiàn)已成為 Apache 頂級(jí)項(xiàng)目。ZooKeeper 是一個(gè)開源的分布式應(yīng)用程序協(xié)調(diào)服務(wù)器,其為分布式系統(tǒng)提供一致性服務(wù)。其一致性是通過基于 Paxos 算法的 ZAB 協(xié)議完成的。其主要功能包括:配置維護(hù)、分布式同步、集群管理、分布式事務(wù)等。

簡(jiǎn)單來說, ZooKeeper 是一個(gè) 分布式協(xié)調(diào)服務(wù)框架 。分布式?協(xié)調(diào)服務(wù)?這啥玩意?
其實(shí)解釋到分布式這個(gè)概念的時(shí)候,我發(fā)現(xiàn)有些同學(xué)并不是能把 **分布式和集群 **這兩個(gè)概念很好的理解透。前段時(shí)間有同學(xué)和我探討起分布式的東西,他說分布式不就是加機(jī)器嗎?一臺(tái)機(jī)器不夠用再加一臺(tái)抗壓?jiǎn)h。當(dāng)然加機(jī)器這種說法也無可厚非,你一個(gè)分布式系統(tǒng)必定涉及到多個(gè)機(jī)器,但是你別忘了,計(jì)算機(jī)學(xué)科中還有一個(gè)相似的概念—— Cluster ,集群不也是加機(jī)器嗎?但是 集群 和 分布式 其實(shí)就是兩個(gè)完全不同的概念。
比如,我現(xiàn)在有一個(gè)秒殺服務(wù),并發(fā)量太大單機(jī)系統(tǒng)承受不住,那我加幾臺(tái)服務(wù)器也 一樣 提供秒殺服務(wù),這個(gè)時(shí)候就是 Cluster 集群 。

但是,我現(xiàn)在換一種方式,我將一個(gè)秒殺服務(wù) 拆分成多個(gè)子服務(wù) ,比如創(chuàng)建訂單服務(wù),增加積分服務(wù),扣優(yōu)惠券服務(wù)等等,然后我將這些子服務(wù)都部署在不同的服務(wù)器上 ,這個(gè)時(shí)候就是 Distributed 分布式 。

而我為什么反駁同學(xué)所說的分布式就是加機(jī)器呢?因?yàn)槲艺J(rèn)為加機(jī)器更加適用于構(gòu)建集群,因?yàn)樗媸侵挥屑訖C(jī)器。而對(duì)于分布式來說,你首先需要將業(yè)務(wù)進(jìn)行拆分,然后再加機(jī)器(不僅僅是加機(jī)器那么簡(jiǎn)單),同時(shí)你還要去解決分布式帶來的一系列問題。

比如各個(gè)分布式組件如何協(xié)調(diào)起來,如何減少各個(gè)系統(tǒng)之間的耦合度,分布式事務(wù)的處理,如何去配置整個(gè)分布式系統(tǒng)等等。ZooKeeper 主要就是解決這些問題的。
3. 一致性問題
設(shè)計(jì)一個(gè)分布式系統(tǒng)必定會(huì)遇到一個(gè)問題—— 因?yàn)榉謪^(qū)容忍性(partition tolerance)的存在,就必定要求我們需要在系統(tǒng)可用性(availability)和數(shù)據(jù)一致性(consistency)中做出權(quán)衡 。這就是著名的 CAP 定理。
理解起來其實(shí)很簡(jiǎn)單,比如說把一個(gè)班級(jí)作為整個(gè)系統(tǒng),而學(xué)生是系統(tǒng)中的一個(gè)個(gè)獨(dú)立的子系統(tǒng)。這個(gè)時(shí)候班里的小紅小明偷偷談戀愛被班里的大嘴巴小花發(fā)現(xiàn)了,小花欣喜若狂告訴了周圍的人,然后小紅小明談戀愛的消息在班級(jí)里傳播起來了。當(dāng)在消息的傳播(散布)過程中,你抓到一個(gè)同學(xué)問他們的情況,如果回答你不知道,那么說明整個(gè)班級(jí)系統(tǒng)出現(xiàn)了數(shù)據(jù)不一致的問題(因?yàn)樾』ㄒ呀?jīng)知道這個(gè)消息了)。而如果他直接不回答你,因?yàn)檎麄€(gè)班級(jí)有消息在進(jìn)行傳播(為了保證一致性,需要所有人都知道才可提供服務(wù)),這個(gè)時(shí)候就出現(xiàn)了系統(tǒng)的可用性問題。

而上述前者就是 Eureka 的處理方式,它保證了AP(可用性),后者就是我們今天所要講的 ZooKeeper 的處理方式,它保證了CP(數(shù)據(jù)一致性)。
4. 一致性協(xié)議和算法
而為了解決數(shù)據(jù)一致性問題,在科學(xué)家和程序員的不斷探索中,就出現(xiàn)了很多的一致性協(xié)議和算法。比如 2PC(兩階段提交),3PC(三階段提交),Paxos算法等等。
這時(shí)候請(qǐng)你思考一個(gè)問題,同學(xué)之間如果采用傳紙條的方式去傳播消息,那么就會(huì)出現(xiàn)一個(gè)問題——我咋知道我的小紙條有沒有傳到我想要傳遞的那個(gè)人手中呢?萬一被哪個(gè)小家伙給劫持篡改了呢,對(duì)吧?

這個(gè)時(shí)候就引申出一個(gè)概念—— 拜占庭將軍問題 。它意指 在不可靠信道上試圖通過消息傳遞的方式達(dá)到一致性是不可能的, 所以所有的一致性算法的 必要前提 就是安全可靠的消息通道。
而為什么要去解決數(shù)據(jù)一致性的問題?你想想,如果一個(gè)秒殺系統(tǒng)將服務(wù)拆分成了下訂單和加積分服務(wù),這兩個(gè)服務(wù)部署在不同的機(jī)器上了,萬一在消息的傳播過程中積分系統(tǒng)宕機(jī)了,總不能你這邊下了訂單卻沒加積分吧?你總得保證兩邊的數(shù)據(jù)需要一致吧?
4.1. 2PC(兩階段提交)
兩階段提交是一種保證分布式系統(tǒng)數(shù)據(jù)一致性的協(xié)議,現(xiàn)在很多數(shù)據(jù)庫(kù)都是采用的兩階段提交協(xié)議來完成 分布式事務(wù) 的處理。
在介紹2PC之前,我們先來想想分布式事務(wù)到底有什么問題呢?
還拿秒殺系統(tǒng)的下訂單和加積分兩個(gè)系統(tǒng)來舉例吧(我想你們可能都吐了),我們此時(shí)下完訂單會(huì)發(fā)個(gè)消息給積分系統(tǒng)告訴它下面該增加積分了。如果我們僅僅是發(fā)送一個(gè)消息也不收回復(fù),那么我們的訂單系統(tǒng)怎么能知道積分系統(tǒng)的收到消息的情況呢?如果我們?cè)黾右粋€(gè)收回復(fù)的過程,那么當(dāng)積分系統(tǒng)收到消息后返回給訂單系統(tǒng)一個(gè) Response ,但在中間出現(xiàn)了網(wǎng)絡(luò)波動(dòng),那個(gè)回復(fù)消息沒有發(fā)送成功,訂單系統(tǒng)是不是以為積分系統(tǒng)消息接收失敗了?它是不是會(huì)回滾事務(wù)?但此時(shí)積分系統(tǒng)是成功收到消息的,它就會(huì)去處理消息然后給用戶增加積分,這個(gè)時(shí)候就會(huì)出現(xiàn)積分加了但是訂單沒下成功。
所以我們所需要解決的是在分布式系統(tǒng)中,整個(gè)調(diào)用鏈中,我們所有服務(wù)的數(shù)據(jù)處理要么都成功要么都失敗,即所有服務(wù)的 原子性問題 。
在兩階段提交中,主要涉及到兩個(gè)角色,分別是協(xié)調(diào)者和參與者。
第一階段:當(dāng)要執(zhí)行一個(gè)分布式事務(wù)的時(shí)候,事務(wù)發(fā)起者首先向協(xié)調(diào)者發(fā)起事務(wù)請(qǐng)求,然后協(xié)調(diào)者會(huì)給所有參與者發(fā)送 prepare 請(qǐng)求(其中包括事務(wù)內(nèi)容)告訴參與者你們需要執(zhí)行事務(wù)了,如果能執(zhí)行我發(fā)的事務(wù)內(nèi)容那么就先執(zhí)行但不提交,執(zhí)行后請(qǐng)給我回復(fù)。然后參與者收到 prepare 消息后,他們會(huì)開始執(zhí)行事務(wù)(但不提交),并將 Undo 和 Redo 信息記入事務(wù)日志中,之后參與者就向協(xié)調(diào)者反饋是否準(zhǔn)備好了。
第二階段:第二階段主要是協(xié)調(diào)者根據(jù)參與者反饋的情況來決定接下來是否可以進(jìn)行事務(wù)的提交操作,即提交事務(wù)或者回滾事務(wù)。
比如這個(gè)時(shí)候 所有的參與者 都返回了準(zhǔn)備好了的消息,這個(gè)時(shí)候就進(jìn)行事務(wù)的提交,協(xié)調(diào)者此時(shí)會(huì)給所有的參與者發(fā)送 Commit 請(qǐng)求 ,當(dāng)參與者收到 Commit 請(qǐng)求的時(shí)候會(huì)執(zhí)行前面執(zhí)行的事務(wù)的 提交操作 ,提交完畢之后將給協(xié)調(diào)者發(fā)送提交成功的響應(yīng)。
而如果在第一階段并不是所有參與者都返回了準(zhǔn)備好了的消息,那么此時(shí)協(xié)調(diào)者將會(huì)給所有參與者發(fā)送 回滾事務(wù)的 rollback 請(qǐng)求,參與者收到之后將會(huì) 回滾它在第一階段所做的事務(wù)處理 ,然后再將處理情況返回給協(xié)調(diào)者,最終協(xié)調(diào)者收到響應(yīng)后便給事務(wù)發(fā)起者返回處理失敗的結(jié)果。

個(gè)人覺得 2PC 實(shí)現(xiàn)得還是比較雞肋的,因?yàn)槭聦?shí)上它只解決了各個(gè)事務(wù)的原子性問題,隨之也帶來了很多的問題。

- 單點(diǎn)故障問題,如果協(xié)調(diào)者掛了那么整個(gè)系統(tǒng)都處于不可用的狀態(tài)了。
-
阻塞問題,即當(dāng)協(xié)調(diào)者發(fā)送
prepare請(qǐng)求,參與者收到之后如果能處理那么它將會(huì)進(jìn)行事務(wù)的處理但并不提交,這個(gè)時(shí)候會(huì)一直占用著資源不釋放,如果此時(shí)協(xié)調(diào)者掛了,那么這些資源都不會(huì)再釋放了,這會(huì)極大影響性能。 -
數(shù)據(jù)不一致問題,比如當(dāng)?shù)诙A段,協(xié)調(diào)者只發(fā)送了一部分的
commit請(qǐng)求就掛了,那么也就意味著,收到消息的參與者會(huì)進(jìn)行事務(wù)的提交,而后面沒收到的則不會(huì)進(jìn)行事務(wù)提交,那么這時(shí)候就會(huì)產(chǎn)生數(shù)據(jù)不一致性問題。
4.2. 3PC(三階段提交)
因?yàn)?PC存在的一系列問題,比如單點(diǎn),容錯(cuò)機(jī)制缺陷等等,從而產(chǎn)生了 3PC(三階段提交) 。那么這三階段又分別是什么呢?
千萬不要吧PC理解成個(gè)人電腦了,其實(shí)他們是 phase-commit 的縮寫,即階段提交。
-
CanCommit階段:協(xié)調(diào)者向所有參與者發(fā)送
CanCommit請(qǐng)求,參與者收到請(qǐng)求后會(huì)根據(jù)自身情況查看是否能執(zhí)行事務(wù),如果可以則返回 YES 響應(yīng)并進(jìn)入預(yù)備狀態(tài),否則返回 NO 。 -
PreCommit階段:協(xié)調(diào)者根據(jù)參與者返回的響應(yīng)來決定是否可以進(jìn)行下面的
PreCommit操作。如果上面參與者返回的都是 YES,那么協(xié)調(diào)者將向所有參與者發(fā)送PreCommit預(yù)提交請(qǐng)求,參與者收到預(yù)提交請(qǐng)求后,會(huì)進(jìn)行事務(wù)的執(zhí)行操作,并將Undo和Redo信息寫入事務(wù)日志中 ,最后如果參與者順利執(zhí)行了事務(wù)則給協(xié)調(diào)者返回成功的響應(yīng)。如果在第一階段協(xié)調(diào)者收到了 任何一個(gè) NO 的信息,或者 在一定時(shí)間內(nèi) 并沒有收到全部的參與者的響應(yīng),那么就會(huì)中斷事務(wù),它會(huì)向所有參與者發(fā)送中斷請(qǐng)求(abort),參與者收到中斷請(qǐng)求之后會(huì)立即中斷事務(wù),或者在一定時(shí)間內(nèi)沒有收到協(xié)調(diào)者的請(qǐng)求,它也會(huì)中斷事務(wù)。 -
DoCommit階段:這個(gè)階段其實(shí)和
2PC的第二階段差不多,如果協(xié)調(diào)者收到了所有參與者在PreCommit階段的 YES 響應(yīng),那么協(xié)調(diào)者將會(huì)給所有參與者發(fā)送DoCommit請(qǐng)求,參與者收到DoCommit請(qǐng)求后則會(huì)進(jìn)行事務(wù)的提交工作,完成后則會(huì)給協(xié)調(diào)者返回響應(yīng),協(xié)調(diào)者收到所有參與者返回的事務(wù)提交成功的響應(yīng)之后則完成事務(wù)。若協(xié)調(diào)者在PreCommit階段 收到了任何一個(gè) NO 或者在一定時(shí)間內(nèi)沒有收到所有參與者的響應(yīng) ,那么就會(huì)進(jìn)行中斷請(qǐng)求的發(fā)送,參與者收到中斷請(qǐng)求后則會(huì) 通過上面記錄的回滾日志 來進(jìn)行事務(wù)的回滾操作,并向協(xié)調(diào)者反饋回滾狀況,協(xié)調(diào)者收到參與者返回的消息后,中斷事務(wù)。
這里是
3PC在成功的環(huán)境下的流程圖,你可以看到3PC在很多地方進(jìn)行了超時(shí)中斷的處理,比如協(xié)調(diào)者在指定時(shí)間內(nèi)為收到全部的確認(rèn)消息則進(jìn)行事務(wù)中斷的處理,這樣能 減少同步阻塞的時(shí)間 。還有需要注意的是,3PC在DoCommit階段參與者如未收到協(xié)調(diào)者發(fā)送的提交事務(wù)的請(qǐng)求,它會(huì)在一定時(shí)間內(nèi)進(jìn)行事務(wù)的提交。為什么這么做呢?是因?yàn)檫@個(gè)時(shí)候我們肯定保證了在第一階段所有的協(xié)調(diào)者全部返回了可以執(zhí)行事務(wù)的響應(yīng),這個(gè)時(shí)候我們有理由相信其他系統(tǒng)都能進(jìn)行事務(wù)的執(zhí)行和提交,所以不管協(xié)調(diào)者有沒有發(fā)消息給參與者,進(jìn)入第三階段參與者都會(huì)進(jìn)行事務(wù)的提交操作。
總之,3PC 通過一系列的超時(shí)機(jī)制很好的緩解了阻塞問題,但是最重要的一致性并沒有得到根本的解決,比如在 PreCommit 階段,當(dāng)一個(gè)參與者收到了請(qǐng)求之后其他參與者和協(xié)調(diào)者掛了或者出現(xiàn)了網(wǎng)絡(luò)分區(qū),這個(gè)時(shí)候收到消息的參與者都會(huì)進(jìn)行事務(wù)提交,這就會(huì)出現(xiàn)數(shù)據(jù)不一致性問題。
所以,要解決一致性問題還需要靠 Paxos 算法。
4.3. Paxos 算法
Paxos 算法是基于消息傳遞且具有高度容錯(cuò)特性的一致性算法,是目前公認(rèn)的解決分布式一致性問題最有效的算法之一,其解決的問題就是在分布式系統(tǒng)中如何就某個(gè)值(決議)達(dá)成一致 。
在 Paxos 中主要有三個(gè)角色,分別為 Proposer提案者、Acceptor表決者、Learner學(xué)習(xí)者。Paxos 算法和 2PC 一樣,也有兩個(gè)階段,分別為 Prepare 和 accept 階段。
4.3.1. prepare 階段
-
Proposer提案者:負(fù)責(zé)提出proposal,每個(gè)提案者在提出提案時(shí)都會(huì)首先獲取到一個(gè) 具有全局唯一性的、遞增的提案編號(hào)N,即在整個(gè)集群中是唯一的編號(hào) N,然后將該編號(hào)賦予其要提出的提案,在第一階段是只將提案編號(hào)發(fā)送給所有的表決者。 -
Acceptor表決者:每個(gè)表決者在accept某提案后,會(huì)將該提案編號(hào)N記錄在本地,這樣每個(gè)表決者中保存的已經(jīng)被 accept 的提案中會(huì)存在一個(gè)編號(hào)最大的提案,其編號(hào)假設(shè)為maxN。每個(gè)表決者僅會(huì)accept編號(hào)大于自己本地maxN的提案,在批準(zhǔn)提案時(shí)表決者會(huì)將以前接受過的最大編號(hào)的提案作為響應(yīng)反饋給Proposer。
下面是
prepare階段的流程圖,你可以對(duì)照著參考一下。
4.3.2. accept 階段
當(dāng)一個(gè)提案被 Proposer 提出后,如果 Proposer 收到了超過半數(shù)的 Acceptor 的批準(zhǔn)(Proposer 本身同意),那么此時(shí) Proposer 會(huì)給所有的 Acceptor 發(fā)送真正的提案(你可以理解為第一階段為試探),這個(gè)時(shí)候 Proposer 就會(huì)發(fā)送提案的內(nèi)容和提案編號(hào)。
表決者收到提案請(qǐng)求后會(huì)再次比較本身已經(jīng)批準(zhǔn)過的最大提案編號(hào)和該提案編號(hào),如果該提案編號(hào) 大于等于 已經(jīng)批準(zhǔn)過的最大提案編號(hào),那么就 accept 該提案(此時(shí)執(zhí)行提案內(nèi)容但不提交),隨后將情況返回給 Proposer 。如果不滿足則不回應(yīng)或者返回 NO 。

當(dāng) Proposer 收到超過半數(shù)的 accept ,那么它這個(gè)時(shí)候會(huì)向所有的 acceptor 發(fā)送提案的提交請(qǐng)求。需要注意的是,因?yàn)樯鲜鰞H僅是超過半數(shù)的 acceptor 批準(zhǔn)執(zhí)行了該提案內(nèi)容,其他沒有批準(zhǔn)的并沒有執(zhí)行該提案內(nèi)容,所以這個(gè)時(shí)候需要向未批準(zhǔn)的 acceptor 發(fā)送提案內(nèi)容和提案編號(hào)并讓它無條件執(zhí)行和提交,而對(duì)于前面已經(jīng)批準(zhǔn)過該提案的 acceptor 來說 僅僅需要發(fā)送該提案的編號(hào) ,讓 acceptor 執(zhí)行提交就行了。

而如果 Proposer 如果沒有收到超過半數(shù)的 accept 那么它將會(huì)將 遞增 該 Proposal 的編號(hào),然后 重新進(jìn)入 Prepare 階段 。
對(duì)于
Learner來說如何去學(xué)習(xí)Acceptor批準(zhǔn)的提案內(nèi)容,這有很多方式,讀者可以自己去了解一下,這里不做過多解釋。
4.3.3. paxos 算法的死循環(huán)問題
其實(shí)就有點(diǎn)類似于兩個(gè)人吵架,小明說我是對(duì)的,小紅說我才是對(duì)的,兩個(gè)人據(jù)理力爭(zhēng)的誰也不讓誰 。
比如說,此時(shí)提案者 P1 提出一個(gè)方案 M1,完成了 Prepare 階段的工作,這個(gè)時(shí)候 acceptor 則批準(zhǔn)了 M1,但是此時(shí)提案者 P2 同時(shí)也提出了一個(gè)方案 M2,它也完成了 Prepare 階段的工作。然后 P1 的方案已經(jīng)不能在第二階段被批準(zhǔn)了(因?yàn)?acceptor 已經(jīng)批準(zhǔn)了比 M1 更大的 M2),所以 P1 自增方案變?yōu)?M3 重新進(jìn)入 Prepare 階段,然后 acceptor ,又批準(zhǔn)了新的 M3 方案,它又不能批準(zhǔn) M2 了,這個(gè)時(shí)候 M2 又自增進(jìn)入 Prepare 階段。。。
就這樣無休無止的永遠(yuǎn)提案下去,這就是 paxos 算法的死循環(huán)問題。

那么如何解決呢?很簡(jiǎn)單,人多了容易吵架,我現(xiàn)在 就允許一個(gè)能提案 就行了。
5. 引出 ZAB
5.1. Zookeeper 架構(gòu)
作為一個(gè)優(yōu)秀高效且可靠的分布式協(xié)調(diào)框架,ZooKeeper 在解決分布式數(shù)據(jù)一致性問題時(shí)并沒有直接使用 Paxos ,而是專門定制了一致性協(xié)議叫做 ZAB(ZooKeeper Automic Broadcast) 原子廣播協(xié)議,該協(xié)議能夠很好地支持 崩潰恢復(fù) 。

5.2. ZAB 中的三個(gè)角色
和介紹 Paxos 一樣,在介紹 ZAB 協(xié)議之前,我們首先來了解一下在 ZAB 中三個(gè)主要的角色,Leader 領(lǐng)導(dǎo)者、Follower跟隨者、Observer觀察者 。
-
Leader:集群中 唯一的寫請(qǐng)求處理者 ,能夠發(fā)起投票(投票也是為了進(jìn)行寫請(qǐng)求)。 -
Follower:能夠接收客戶端的請(qǐng)求,如果是讀請(qǐng)求則可以自己處理,如果是寫請(qǐng)求則要轉(zhuǎn)發(fā)給Leader。在選舉過程中會(huì)參與投票,有選舉權(quán)和被選舉權(quán) 。 -
Observer:就是沒有選舉權(quán)和被選舉權(quán)的Follower。
在 ZAB 協(xié)議中對(duì) zkServer(即上面我們說的三個(gè)角色的總稱) 還有兩種模式的定義,分別是 消息廣播 和 崩潰恢復(fù) 。
5.3. 消息廣播模式
說白了就是 ZAB 協(xié)議是如何處理寫請(qǐng)求的,上面我們不是說只有 Leader 能處理寫請(qǐng)求嘛?那么我們的 Follower 和 Observer 是不是也需要 同步更新數(shù)據(jù) 呢?總不能數(shù)據(jù)只在 Leader 中更新了,其他角色都沒有得到更新吧?
不就是 在整個(gè)集群中保持?jǐn)?shù)據(jù)的一致性 嘛?如果是你,你會(huì)怎么做呢?

廢話,第一步肯定需要 Leader 將寫請(qǐng)求 廣播 出去呀,讓 Leader 問問 Followers 是否同意更新,如果超過半數(shù)以上的同意那么就進(jìn)行 Follower 和 Observer 的更新(和 Paxos 一樣)。當(dāng)然這么說有點(diǎn)虛,畫張圖理解一下。

嗯。。??雌饋砗芎?jiǎn)單,貌似懂了。這兩個(gè) Queue 哪冒出來的?答案是 ZAB 需要讓 Follower 和 Observer 保證順序性 。何為順序性,比如我現(xiàn)在有一個(gè)寫請(qǐng)求A,此時(shí) Leader 將請(qǐng)求A廣播出去,因?yàn)橹恍枰霐?shù)同意就行,所以可能這個(gè)時(shí)候有一個(gè) Follower F1因?yàn)榫W(wǎng)絡(luò)原因沒有收到,而 Leader 又廣播了一個(gè)請(qǐng)求B,因?yàn)榫W(wǎng)絡(luò)原因,F(xiàn)1竟然先收到了請(qǐng)求B然后才收到了請(qǐng)求A,這個(gè)時(shí)候請(qǐng)求處理的順序不同就會(huì)導(dǎo)致數(shù)據(jù)的不同,從而 產(chǎn)生數(shù)據(jù)不一致問題 。
所以在 Leader 這端,它為每個(gè)其他的 zkServer 準(zhǔn)備了一個(gè) 隊(duì)列 ,采用先進(jìn)先出的方式發(fā)送消息。由于協(xié)議是 **通過 TCP **來進(jìn)行網(wǎng)絡(luò)通信的,保證了消息的發(fā)送順序性,接受順序性也得到了保證。
除此之外,在 ZAB 中還定義了一個(gè) 全局單調(diào)遞增的事務(wù)ID ZXID ,它是一個(gè)64位long型,其中高32位表示 epoch 年代,低32位表示事務(wù)id。epoch 是會(huì)根據(jù) Leader 的變化而變化的,當(dāng)一個(gè) Leader 掛了,新的 Leader 上位的時(shí)候,年代(epoch)就變了。而低32位可以簡(jiǎn)單理解為遞增的事務(wù)id。
定義這個(gè)的原因也是為了順序性,每個(gè) proposal 在 Leader 中生成后需要 通過其 ZXID 來進(jìn)行排序 ,才能得到處理。
5.4. 崩潰恢復(fù)模式
說到崩潰恢復(fù)我們首先要提到 ZAB 中的 Leader 選舉算法,當(dāng)系統(tǒng)出現(xiàn)崩潰影響最大應(yīng)該是 Leader 的崩潰,因?yàn)槲覀冎挥幸粋€(gè) Leader ,所以當(dāng) Leader 出現(xiàn)問題的時(shí)候我們勢(shì)必需要重新選舉 Leader 。
Leader 選舉可以分為兩個(gè)不同的階段,第一個(gè)是我們提到的 Leader 宕機(jī)需要重新選舉,第二則是當(dāng) Zookeeper 啟動(dòng)時(shí)需要進(jìn)行系統(tǒng)的 Leader 初始化選舉。下面我先來介紹一下 ZAB 是如何進(jìn)行初始化選舉的。
假設(shè)我們集群中有3臺(tái)機(jī)器,那也就意味著我們需要兩臺(tái)以上同意(超過半數(shù))。比如這個(gè)時(shí)候我們啟動(dòng)了 server1 ,它會(huì)首先 投票給自己 ,投票內(nèi)容為服務(wù)器的 myid 和 ZXID ,因?yàn)槌跏蓟?ZXID 都為0,此時(shí) server1 發(fā)出的投票為 (1,0)。但此時(shí) server1 的投票僅為1,所以不能作為 Leader ,此時(shí)還在選舉階段所以整個(gè)集群處于 Looking 狀態(tài)。
接著 server2 啟動(dòng)了,它首先也會(huì)將投票選給自己(2,0),并將投票信息廣播出去(server1也會(huì),只是它那時(shí)沒有其他的服務(wù)器了),server1 在收到 server2 的投票信息后會(huì)將投票信息與自己的作比較。首先它會(huì)比較 ZXID ,ZXID 大的優(yōu)先為 Leader,如果相同則比較 myid,myid 大的優(yōu)先作為 Leader。所以此時(shí)server1 發(fā)現(xiàn) server2 更適合做 Leader,它就會(huì)將自己的投票信息更改為(2,0)然后再?gòu)V播出去,之后server2 收到之后發(fā)現(xiàn)和自己的一樣無需做更改,并且自己的 投票已經(jīng)超過半數(shù) ,則 確定 server2 為 Leader,server1 也會(huì)將自己服務(wù)器設(shè)置為 Following 變?yōu)?Follower。整個(gè)服務(wù)器就從 Looking 變?yōu)榱苏顟B(tài)。
當(dāng) server3 啟動(dòng)發(fā)現(xiàn)集群沒有處于 Looking 狀態(tài)時(shí),它會(huì)直接以 Follower 的身份加入集群。
還是前面三個(gè) server 的例子,如果在整個(gè)集群運(yùn)行的過程中 server2 掛了,那么整個(gè)集群會(huì)如何重新選舉 Leader 呢?其實(shí)和初始化選舉差不多。
首先毫無疑問的是剩下的兩個(gè) Follower 會(huì)將自己的狀態(tài) 從 Following 變?yōu)?Looking 狀態(tài) ,然后每個(gè) server 會(huì)向初始化投票一樣首先給自己投票(這不過這里的 zxid 可能不是0了,這里為了方便隨便取個(gè)數(shù)字)。
假設(shè) server1 給自己投票為(1,99),然后廣播給其他 server,server3 首先也會(huì)給自己投票(3,95),然后也廣播給其他 server。server1 和 server3 此時(shí)會(huì)收到彼此的投票信息,和一開始選舉一樣,他們也會(huì)比較自己的投票和收到的投票(zxid 大的優(yōu)先,如果相同那么就 myid 大的優(yōu)先)。這個(gè)時(shí)候 server1 收到了 server3 的投票發(fā)現(xiàn)沒自己的合適故不變,server3 收到 server1 的投票結(jié)果后發(fā)現(xiàn)比自己的合適于是更改投票為(1,99)然后廣播出去,最后 server1 收到了發(fā)現(xiàn)自己的投票已經(jīng)超過半數(shù)就把自己設(shè)為 Leader,server3 也隨之變?yōu)?Follower。
請(qǐng)注意
ZooKeeper為什么要設(shè)置奇數(shù)個(gè)結(jié)點(diǎn)?比如這里我們是三個(gè),掛了一個(gè)我們還能正常工作,掛了兩個(gè)我們就不能正常工作了(已經(jīng)沒有超過半數(shù)的節(jié)點(diǎn)數(shù)了,所以無法進(jìn)行投票等操作了)。而假設(shè)我們現(xiàn)在有四個(gè),掛了一個(gè)也能工作,但是掛了兩個(gè)也不能正常工作了,這是和三個(gè)一樣的,而三個(gè)比四個(gè)還少一個(gè),帶來的效益是一樣的,所以Zookeeper推薦奇數(shù)個(gè)server。
那么說完了 ZAB 中的 Leader 選舉方式之后我們?cè)賮砹私庖幌?崩潰恢復(fù) 是什么玩意?
其實(shí)主要就是 當(dāng)集群中有機(jī)器掛了,我們整個(gè)集群如何保證數(shù)據(jù)一致性?
如果只是 Follower 掛了,而且掛的沒超過半數(shù)的時(shí)候,因?yàn)槲覀円婚_始講了在 Leader 中會(huì)維護(hù)隊(duì)列,所以不用擔(dān)心后面的數(shù)據(jù)沒接收到導(dǎo)致數(shù)據(jù)不一致性。
如果 Leader 掛了那就麻煩了,我們肯定需要先暫停服務(wù)變?yōu)?Looking 狀態(tài)然后進(jìn)行 Leader 的重新選舉(上面我講過了),但這個(gè)就要分為兩種情況了,分別是 確保已經(jīng)被Leader提交的提案最終能夠被所有的Follower提交 和 跳過那些已經(jīng)被丟棄的提案 。
確保已經(jīng)被Leader提交的提案最終能夠被所有的Follower提交是什么意思呢?
假設(shè) Leader (server2) 發(fā)送 commit 請(qǐng)求(忘了請(qǐng)看上面的消息廣播模式),他發(fā)送給了 server3,然后要發(fā)給 server1 的時(shí)候突然掛了。這個(gè)時(shí)候重新選舉的時(shí)候我們?nèi)绻?server1 作為 Leader 的話,那么肯定會(huì)產(chǎn)生數(shù)據(jù)不一致性,因?yàn)?server3 肯定會(huì)提交剛剛 server2 發(fā)送的 commit 請(qǐng)求的提案,而 server1 根本沒收到所以會(huì)丟棄。

那怎么解決呢?
聰明的同學(xué)肯定會(huì)質(zhì)疑,這個(gè)時(shí)候 server1 已經(jīng)不可能成為 Leader 了,因?yàn)?server1 和 server3 進(jìn)行投票選舉的時(shí)候會(huì)比較 ZXID ,而此時(shí) server3 的 ZXID 肯定比 server1 的大了。(不理解可以看前面的選舉算法)
那么跳過那些已經(jīng)被丟棄的提案又是什么意思呢?
假設(shè) Leader (server2) 此時(shí)同意了提案N1,自身提交了這個(gè)事務(wù)并且要發(fā)送給所有 Follower 要 commit 的請(qǐng)求,卻在這個(gè)時(shí)候掛了,此時(shí)肯定要重新進(jìn)行 Leader 的選舉,比如說此時(shí)選 server1 為 Leader (這無所謂)。但是過了一會(huì),這個(gè) 掛掉的 Leader 又重新恢復(fù)了 ,此時(shí)它肯定會(huì)作為 Follower 的身份進(jìn)入集群中,需要注意的是剛剛 server2 已經(jīng)同意提交了提案N1,但其他 server 并沒有收到它的 commit 信息,所以其他 server 不可能再提交這個(gè)提案N1了,這樣就會(huì)出現(xiàn)數(shù)據(jù)不一致性問題了,所以 該提案N1最終需要被拋棄掉 。

6. Zookeeper的幾個(gè)理論知識(shí)
了解了 ZAB 協(xié)議還不夠,它僅僅是 Zookeeper 內(nèi)部實(shí)現(xiàn)的一種方式,而我們?nèi)绾瓮ㄟ^ Zookeeper 去做一些典型的應(yīng)用場(chǎng)景呢?比如說集群管理,分布式鎖,Master 選舉等等。
這就涉及到如何使用 Zookeeper 了,但在使用之前我們還需要掌握幾個(gè)概念。比如 Zookeeper 的 數(shù)據(jù)模型 、會(huì)話機(jī)制、ACL、Watcher機(jī)制 等等。
6.1. 數(shù)據(jù)模型
zookeeper 數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)與標(biāo)準(zhǔn)的 Unix 文件系統(tǒng)非常相似,都是在根節(jié)點(diǎn)下掛很多子節(jié)點(diǎn)(樹型)。但是 zookeeper 中沒有文件系統(tǒng)中目錄與文件的概念,而是 使用了 znode 作為數(shù)據(jù)節(jié)點(diǎn) 。znode 是 zookeeper 中的最小數(shù)據(jù)單元,每個(gè) znode 上都可以保存數(shù)據(jù),同時(shí)還可以掛載子節(jié)點(diǎn),形成一個(gè)樹形化命名空間。

每個(gè) znode 都有自己所屬的 節(jié)點(diǎn)類型 和 節(jié)點(diǎn)狀態(tài)。
其中節(jié)點(diǎn)類型可以分為 持久節(jié)點(diǎn)、持久順序節(jié)點(diǎn)、臨時(shí)節(jié)點(diǎn) 和 臨時(shí)順序節(jié)點(diǎn)。
- 持久節(jié)點(diǎn):一旦創(chuàng)建就一直存在,直到將其刪除。
- 持久順序節(jié)點(diǎn):一個(gè)父節(jié)點(diǎn)可以為其子節(jié)點(diǎn) 維護(hù)一個(gè)創(chuàng)建的先后順序 ,這個(gè)順序體現(xiàn)在 節(jié)點(diǎn)名稱 上,是節(jié)點(diǎn)名稱后自動(dòng)添加一個(gè)由 10 位數(shù)字組成的數(shù)字串,從 0 開始計(jì)數(shù)。
- 臨時(shí)節(jié)點(diǎn):臨時(shí)節(jié)點(diǎn)的生命周期是與 客戶端會(huì)話 綁定的,會(huì)話消失則節(jié)點(diǎn)消失 。臨時(shí)節(jié)點(diǎn) 只能做葉子節(jié)點(diǎn) ,不能創(chuàng)建子節(jié)點(diǎn)。
- 臨時(shí)順序節(jié)點(diǎn):父節(jié)點(diǎn)可以創(chuàng)建一個(gè)維持了順序的臨時(shí)節(jié)點(diǎn)(和前面的持久順序性節(jié)點(diǎn)一樣)。
節(jié)點(diǎn)狀態(tài)中包含了很多節(jié)點(diǎn)的屬性比如 czxid 、mzxid 等等,在 zookeeper 中是使用 Stat 這個(gè)類來維護(hù)的。下面我列舉一些屬性解釋。
-
czxid:Created ZXID,該數(shù)據(jù)節(jié)點(diǎn)被 創(chuàng)建 時(shí)的事務(wù)ID。 -
mzxid:Modified ZXID,節(jié)點(diǎn) 最后一次被更新時(shí) 的事務(wù)ID。 -
ctime:Created Time,該節(jié)點(diǎn)被創(chuàng)建的時(shí)間。 -
mtime:Modified Time,該節(jié)點(diǎn)最后一次被修改的時(shí)間。 -
version:節(jié)點(diǎn)的版本號(hào)。 -
cversion:子節(jié)點(diǎn) 的版本號(hào)。 -
aversion:節(jié)點(diǎn)的ACL版本號(hào)。 -
ephemeralOwner:創(chuàng)建該節(jié)點(diǎn)的會(huì)話的sessionID,如果該節(jié)點(diǎn)為持久節(jié)點(diǎn),該值為0。 -
dataLength:節(jié)點(diǎn)數(shù)據(jù)內(nèi)容的長(zhǎng)度。 -
numChildre:該節(jié)點(diǎn)的子節(jié)點(diǎn)個(gè)數(shù),如果為臨時(shí)節(jié)點(diǎn)為0。 -
pzxid:該節(jié)點(diǎn)子節(jié)點(diǎn)列表最后一次被修改時(shí)的事務(wù)ID,注意是子節(jié)點(diǎn)的 列表 ,不是內(nèi)容。
6.2. 會(huì)話
我想這個(gè)對(duì)于后端開發(fā)的朋友肯定不陌生,不就是 session 嗎?只不過 zk 客戶端和服務(wù)端是通過 TCP 長(zhǎng)連接 維持的會(huì)話機(jī)制,其實(shí)對(duì)于會(huì)話來說你可以理解為 保持連接狀態(tài) 。
在 zookeeper 中,會(huì)話還有對(duì)應(yīng)的事件,比如 CONNECTION_LOSS 連接丟失事件 、SESSION_MOVED 會(huì)話轉(zhuǎn)移事件 、SESSION_EXPIRED 會(huì)話超時(shí)失效事件 。
6.3. ACL
ACL 為 Access Control Lists ,它是一種權(quán)限控制。在 zookeeper 中定義了5種權(quán)限,它們分別為:
-
CREATE:創(chuàng)建子節(jié)點(diǎn)的權(quán)限。 -
READ:獲取節(jié)點(diǎn)數(shù)據(jù)和子節(jié)點(diǎn)列表的權(quán)限。 -
WRITE:更新節(jié)點(diǎn)數(shù)據(jù)的權(quán)限。 -
DELETE:刪除子節(jié)點(diǎn)的權(quán)限。 -
ADMIN:設(shè)置節(jié)點(diǎn) ACL 的權(quán)限。
6.4. Watcher機(jī)制
Watcher 為事件監(jiān)聽器,是 zk 非常重要的一個(gè)特性,很多功能都依賴于它,它有點(diǎn)類似于訂閱的方式,即客戶端向服務(wù)端 注冊(cè) 指定的 watcher ,當(dāng)服務(wù)端符合了 watcher 的某些事件或要求則會(huì) 向客戶端發(fā)送事件通知 ,客戶端收到通知后找到自己定義的 Watcher 然后 執(zhí)行相應(yīng)的回調(diào)方法 。

7. Zookeeper的幾個(gè)典型應(yīng)用場(chǎng)景
前面說了這么多的理論知識(shí),你可能聽得一頭霧水,這些玩意有啥用?能干啥事?別急,聽我慢慢道來。

7.1. 選主
還記得上面我們的所說的臨時(shí)節(jié)點(diǎn)嗎?因?yàn)?Zookeeper 的強(qiáng)一致性,能夠很好地在保證 在高并發(fā)的情況下保證節(jié)點(diǎn)創(chuàng)建的全局唯一性 (即無法重復(fù)創(chuàng)建同樣的節(jié)點(diǎn))。
利用這個(gè)特性,我們可以 讓多個(gè)客戶端創(chuàng)建一個(gè)指定的節(jié)點(diǎn) ,創(chuàng)建成功的就是 master。
但是,如果這個(gè) master 掛了怎么辦???
你想想為什么我們要?jiǎng)?chuàng)建臨時(shí)節(jié)點(diǎn)?還記得臨時(shí)節(jié)點(diǎn)的生命周期嗎?master 掛了是不是代表會(huì)話斷了?會(huì)話斷了是不是意味著這個(gè)節(jié)點(diǎn)沒了?還記得 watcher 嗎?我們是不是可以 讓其他不是 master 的節(jié)點(diǎn)監(jiān)聽節(jié)點(diǎn)的狀態(tài) ,比如說我們監(jiān)聽這個(gè)臨時(shí)節(jié)點(diǎn)的父節(jié)點(diǎn),如果子節(jié)點(diǎn)個(gè)數(shù)變了就代表 master 掛了,這個(gè)時(shí)候我們 觸發(fā)回調(diào)函數(shù)進(jìn)行重新選舉 ,或者我們直接監(jiān)聽節(jié)點(diǎn)的狀態(tài),我們可以通過節(jié)點(diǎn)是否已經(jīng)失去連接來判斷 master 是否掛了等等。

總的來說,我們可以完全 利用 臨時(shí)節(jié)點(diǎn)、節(jié)點(diǎn)狀態(tài) 和 watcher 來實(shí)現(xiàn)選主的功能,臨時(shí)節(jié)點(diǎn)主要用來選舉,節(jié)點(diǎn)狀態(tài)和watcher 可以用來判斷 master 的活性和進(jìn)行重新選舉。
7.2. 分布式鎖
分布式鎖的實(shí)現(xiàn)方式有很多種,比如 Redis 、數(shù)據(jù)庫(kù) 、zookeeper 等。個(gè)人認(rèn)為 zookeeper 在實(shí)現(xiàn)分布式鎖這方面是非常非常簡(jiǎn)單的。
上面我們已經(jīng)提到過了 zk在高并發(fā)的情況下保證節(jié)點(diǎn)創(chuàng)建的全局唯一性,這玩意一看就知道能干啥了。實(shí)現(xiàn)互斥鎖唄,又因?yàn)槟茉诜植际降那闆r下,所以能實(shí)現(xiàn)分布式鎖唄。
如何實(shí)現(xiàn)呢?這玩意其實(shí)跟選主基本一樣,我們也可以利用臨時(shí)節(jié)點(diǎn)的創(chuàng)建來實(shí)現(xiàn)。
首先肯定是如何獲取鎖,因?yàn)閯?chuàng)建節(jié)點(diǎn)的唯一性,我們可以讓多個(gè)客戶端同時(shí)創(chuàng)建一個(gè)臨時(shí)節(jié)點(diǎn),創(chuàng)建成功的就說明獲取到了鎖 。然后沒有獲取到鎖的客戶端也像上面選主的非主節(jié)點(diǎn)創(chuàng)建一個(gè) watcher 進(jìn)行節(jié)點(diǎn)狀態(tài)的監(jiān)聽,如果這個(gè)互斥鎖被釋放了(可能獲取鎖的客戶端宕機(jī)了,或者那個(gè)客戶端主動(dòng)釋放了鎖)可以調(diào)用回調(diào)函數(shù)重新獲得鎖。
zk中不需要向redis那樣考慮鎖得不到釋放的問題了,因?yàn)楫?dāng)客戶端掛了,節(jié)點(diǎn)也掛了,鎖也釋放了。是不是很簡(jiǎn)答?
那能不能使用 zookeeper 同時(shí)實(shí)現(xiàn) 共享鎖和獨(dú)占鎖 呢?答案是可以的,不過稍微有點(diǎn)復(fù)雜而已。
還記得 有序的節(jié)點(diǎn) 嗎?
這個(gè)時(shí)候我規(guī)定所有創(chuàng)建節(jié)點(diǎn)必須有序,當(dāng)你是讀請(qǐng)求(要獲取共享鎖)的話,如果 沒有比自己更小的節(jié)點(diǎn),或比自己小的節(jié)點(diǎn)都是讀請(qǐng)求 ,則可以獲取到讀鎖,然后就可以開始讀了。若比自己小的節(jié)點(diǎn)中有寫請(qǐng)求 ,則當(dāng)前客戶端無法獲取到讀鎖,只能等待前面的寫請(qǐng)求完成。
如果你是寫請(qǐng)求(獲取獨(dú)占鎖),若 沒有比自己更小的節(jié)點(diǎn) ,則表示當(dāng)前客戶端可以直接獲取到寫鎖,對(duì)數(shù)據(jù)進(jìn)行修改。若發(fā)現(xiàn) 有比自己更小的節(jié)點(diǎn),無論是讀操作還是寫操作,當(dāng)前客戶端都無法獲取到寫鎖 ,等待所有前面的操作完成。
這就很好地同時(shí)實(shí)現(xiàn)了共享鎖和獨(dú)占鎖,當(dāng)然還有優(yōu)化的地方,比如當(dāng)一個(gè)鎖得到釋放它會(huì)通知所有等待的客戶端從而造成 羊群效應(yīng) 。此時(shí)你可以通過讓等待的節(jié)點(diǎn)只監(jiān)聽他們前面的節(jié)點(diǎn)。
具體怎么做呢?其實(shí)也很簡(jiǎn)單,你可以讓 讀請(qǐng)求監(jiān)聽比自己小的最后一個(gè)寫請(qǐng)求節(jié)點(diǎn),寫請(qǐng)求只監(jiān)聽比自己小的最后一個(gè)節(jié)點(diǎn) ,感興趣的小伙伴可以自己去研究一下。
7.3. 命名服務(wù)
如何給一個(gè)對(duì)象設(shè)置ID,大家可能都會(huì)想到 UUID,但是 UUID 最大的問題就在于它太長(zhǎng)了。。。(太長(zhǎng)不一定是好事,嘿嘿嘿)。那么在條件允許的情況下,我們能不能使用 zookeeper 來實(shí)現(xiàn)呢?
我們之前提到過 zookeeper 是通過 樹形結(jié)構(gòu) 來存儲(chǔ)數(shù)據(jù)節(jié)點(diǎn)的,那也就是說,對(duì)于每個(gè)節(jié)點(diǎn)的 全路徑,它必定是唯一的,我們可以使用節(jié)點(diǎn)的全路徑作為命名方式了。而且更重要的是,路徑是我們可以自己定義的,這對(duì)于我們對(duì)有些有語意的對(duì)象的ID設(shè)置可以更加便于理解。
7.4. 集群管理和注冊(cè)中心
看到這里是不是覺得 zookeeper 實(shí)在是太強(qiáng)大了,它怎么能這么能干!
別急,它能干的事情還很多呢??赡芪覀儠?huì)有這樣的需求,我們需要了解整個(gè)集群中有多少機(jī)器在工作,我們想對(duì)及群眾的每臺(tái)機(jī)器的運(yùn)行時(shí)狀態(tài)進(jìn)行數(shù)據(jù)采集,對(duì)集群中機(jī)器進(jìn)行上下線操作等等。
而 zookeeper 天然支持的 watcher 和 臨時(shí)節(jié)點(diǎn)能很好的實(shí)現(xiàn)這些需求。我們可以為每條機(jī)器創(chuàng)建臨時(shí)節(jié)點(diǎn),并監(jiān)控其父節(jié)點(diǎn),如果子節(jié)點(diǎn)列表有變動(dòng)(我們可能創(chuàng)建刪除了臨時(shí)節(jié)點(diǎn)),那么我們可以使用在其父節(jié)點(diǎn)綁定的 watcher 進(jìn)行狀態(tài)監(jiān)控和回調(diào)。

至于注冊(cè)中心也很簡(jiǎn)單,我們同樣也是讓 服務(wù)提供者 在 zookeeper 中創(chuàng)建一個(gè)臨時(shí)節(jié)點(diǎn)并且將自己的 ip、port、調(diào)用方式 寫入節(jié)點(diǎn),當(dāng) 服務(wù)消費(fèi)者 需要進(jìn)行調(diào)用的時(shí)候會(huì) 通過注冊(cè)中心找到相應(yīng)的服務(wù)的地址列表(IP端口什么的) ,并緩存到本地(方便以后調(diào)用),當(dāng)消費(fèi)者調(diào)用服務(wù)時(shí),不會(huì)再去請(qǐng)求注冊(cè)中心,而是直接通過負(fù)載均衡算法從地址列表中取一個(gè)服務(wù)提供者的服務(wù)器調(diào)用服務(wù)。
當(dāng)服務(wù)提供者的某臺(tái)服務(wù)器宕機(jī)或下線時(shí),相應(yīng)的地址會(huì)從服務(wù)提供者地址列表中移除。同時(shí),注冊(cè)中心會(huì)將新的服務(wù)地址列表發(fā)送給服務(wù)消費(fèi)者的機(jī)器并緩存在消費(fèi)者本機(jī)(當(dāng)然你可以讓消費(fèi)者進(jìn)行節(jié)點(diǎn)監(jiān)聽,我記得 Eureka 會(huì)先試錯(cuò),然后再更新)。

8. 總結(jié)
看到這里的同學(xué)實(shí)在是太有耐心了,如果覺得我寫得不錯(cuò)的話點(diǎn)個(gè)贊哈。
不知道大家是否還記得我講了什么。

這篇文章中我?guī)Т蠹胰腴T了 zookeeper 這個(gè)強(qiáng)大的分布式協(xié)調(diào)框架。現(xiàn)在我們來簡(jiǎn)單梳理一下整篇文章的內(nèi)容。
分布式與集群的區(qū)別
2PC、3PC以及paxos算法這些一致性框架的原理和實(shí)現(xiàn)。zookeeper專門的一致性算法ZAB原子廣播協(xié)議的內(nèi)容(Leader選舉、崩潰恢復(fù)、消息廣播)。zookeeper中的一些基本概念,比如ACL,數(shù)據(jù)節(jié)點(diǎn),會(huì)話,watcher機(jī)制等等。-
zookeeper的典型應(yīng)用場(chǎng)景,比如選主,注冊(cè)中心等等。如果忘了可以回去看看再次理解一下,如果有疑問和建議歡迎提出。
作者:Snailclimb
鏈接:【進(jìn)階】ZooKeeper 相關(guān)概念總結(jié)
來源:github

