????????
目錄
一、分布式一致性原理
二、ZooKeeper架構(gòu)
? ? ? ? 2.1 ZAB 協(xié)議操作順序性
? ? ? ? 2.2 領(lǐng)導(dǎo)者選舉
? ? ? ? 成員身份
? ? ? ? 成員狀態(tài)
? ? ? ? 領(lǐng)導(dǎo)者選舉
三、總結(jié)
????????在分布式系統(tǒng)里的多臺(tái)服務(wù)器要對(duì)數(shù)據(jù)狀態(tài)達(dá)成一致,其實(shí)是一件很有難度和挑戰(zhàn)的事情,因?yàn)榉?wù)器集群環(huán)境的軟硬件故障隨時(shí)會(huì)發(fā)生,多臺(tái)服務(wù)器對(duì)一個(gè)數(shù)據(jù)的記錄保持一致,需要一些技巧和設(shè)計(jì)。
一、分布式一致性原理
? ? ? ? 關(guān)于分布式一致性,相信你肯定聽(tīng)過(guò)著名的 CAP 原理。CAP 原理認(rèn)為,一個(gè)提供數(shù)據(jù)服務(wù)的分布式系統(tǒng)無(wú)法同時(shí)滿足數(shù)據(jù)一致性(Consistency)、可用性(Availibility)、分區(qū)容錯(cuò)性(Patition Tolerance)這三個(gè)條件,如下圖所示。
????????一致性指的是,每次讀取的數(shù)據(jù)都應(yīng)該是最近寫(xiě)入的數(shù)據(jù)或者返回一個(gè)錯(cuò)誤(Every read receives the most recent write or an error),而不是過(guò)期數(shù)據(jù),也就是說(shuō),數(shù)據(jù)是一致的。
????????可用性指的是,每次請(qǐng)求都應(yīng)該得到一個(gè)響應(yīng),而不是返回一個(gè)錯(cuò)誤或者失去響應(yīng),不過(guò)這個(gè)響應(yīng)不需要保證數(shù)據(jù)是最近寫(xiě)入的(Every request receives a (non-error) response, without the guarantee that it contains the most recent write),也就是說(shuō)系統(tǒng)需要一直都是可以正常使用的,不會(huì)引起調(diào)用者的異常,但是并不保證響應(yīng)的數(shù)據(jù)是最新的。
????????分區(qū)容錯(cuò)性指的是,即使因?yàn)榫W(wǎng)絡(luò)原因,部分服務(wù)器節(jié)點(diǎn)之間消息丟失或者延遲了,系統(tǒng)依然應(yīng)該是可以操作的。
????????當(dāng)網(wǎng)絡(luò)分區(qū)失效發(fā)生的時(shí)候,我們要么取消操作,這樣數(shù)據(jù)就是一致的,但是系統(tǒng)卻不可用;要么我們繼續(xù)寫(xiě)入數(shù)據(jù),但是數(shù)據(jù)的一致性就得不到保證。
????????對(duì)于一個(gè)分布式系統(tǒng)而言,網(wǎng)絡(luò)失效一定會(huì)發(fā)生,也就是說(shuō),分區(qū)容錯(cuò)性是必須要保證的,那么在可用性和一致性上就必須二選一。當(dāng)網(wǎng)絡(luò)分區(qū)失效,也就是網(wǎng)絡(luò)不可用的時(shí)候,如果選擇了一致性,系統(tǒng)就可能返回一個(gè)錯(cuò)誤碼或者干脆超時(shí),即系統(tǒng)不可用。如果選擇了可用性,那么系統(tǒng)總是可以返回一個(gè)數(shù)據(jù),但是并不能保證這個(gè)數(shù)據(jù)是最新的。
????????所以,關(guān)于CAP原理,更準(zhǔn)確的說(shuō)法是,在分布式系統(tǒng)必須要滿足分區(qū)耐受性的前提下,可用性和一致性無(wú)法同時(shí)滿足。
二、ZooKeeper架構(gòu)
????????ZooKeeper 主要提供數(shù)據(jù)的一致性服務(wù),分布式系統(tǒng)共識(shí)算法起源于?Paxos 算法。這里假設(shè)你已經(jīng)了解了?Paxos 算法的視線,不了解也沒(méi)關(guān)系,關(guān)于?Paxos 算法具體內(nèi)容請(qǐng)參考往期文章:探索分布式強(qiáng)一致性?shī)W秘:Paxos共識(shí)算法的精妙之旅-CSDN博客
? ? ? ? 那我們能用 Paxos 來(lái)實(shí)現(xiàn) Zookeeper 各節(jié)點(diǎn)的數(shù)據(jù)一致性嗎?答案是否定的,Paxos 算法雖然能保證達(dá)成共識(shí)后的值不再改變,但它不關(guān)心達(dá)成共識(shí)的值是什么,也無(wú)法保證各值(也就是操作)的順序性。而這就是 Zookeeper 沒(méi)有采用?Paxos 的原因,又是 ZAB 協(xié)議著力解決的,也是理解 ZAB 協(xié)議的關(guān)鍵。
? ? ? ? 首先看下 ZooKeeper 的 ZAB 協(xié)議是如何實(shí)現(xiàn)操作順序的?
? ? ? ? 2.1 ZAB 協(xié)議操作順序性
? ? ? ? 如果用一句話來(lái)解釋 ZAB 協(xié)議到底是什么,應(yīng)該是:能保證操作順序性的,基于主備模式的原子廣播協(xié)議。
? ? ? ? 先來(lái)看一個(gè)例子:假如節(jié)點(diǎn) A、B、C 組成的一個(gè)分布式集群,指令(比如 X、Y),我們來(lái)看下 ZAB 是如何保證實(shí)現(xiàn)順序性的,假設(shè) A 為主節(jié)點(diǎn),B、C 為備份節(jié)點(diǎn)。
????????首先,需要注意的是,在 ZAB 中,寫(xiě)操作必須在主節(jié)點(diǎn)(比如節(jié)點(diǎn) A)上執(zhí)行。如果客戶端訪問(wèn)的節(jié)點(diǎn)是備份節(jié)點(diǎn)(比如節(jié)點(diǎn) B),它會(huì)將寫(xiě)請(qǐng)求轉(zhuǎn)發(fā)給主節(jié)點(diǎn)。如圖所示:? ? ? ??
????????接著,當(dāng)主節(jié)點(diǎn)接收到寫(xiě)請(qǐng)求后,它會(huì)基于寫(xiě)請(qǐng)求中的指令(也就是 X,Y),來(lái)創(chuàng)建一個(gè)提案(Proposal),并使用一個(gè)唯一的 ID 來(lái)標(biāo)識(shí)這個(gè)提案。這里的唯一?ID 就是指事務(wù)標(biāo)識(shí)符(Transaction ID,也就是 zxid),如下圖。
????????從圖中可以看到,X、Y 對(duì)應(yīng)的事務(wù)標(biāo)識(shí)符分別為 <1, 1> 和 <1, 2>,這兩個(gè)標(biāo)識(shí)符是什么含義呢?
????????可以這么理解,事務(wù)標(biāo)識(shí)符是 64 位的 long 型變量,有任期編號(hào) epoch 和計(jì)數(shù)器 counter 兩部分組成(為了形象和方便理解,我把 epoch 翻譯成任期編號(hào)),格式為高 32 位為任期編號(hào),低 32 位為計(jì)數(shù)器:
- 任期編號(hào),就是創(chuàng)建提案時(shí)領(lǐng)導(dǎo)者的任期編號(hào),需要注意的是,當(dāng)新領(lǐng)導(dǎo)者當(dāng)選時(shí),任期編號(hào)遞增,計(jì)數(shù)器被設(shè)置為零。比如,前領(lǐng)導(dǎo)者的任期編號(hào)為 1,那么新領(lǐng)導(dǎo)者對(duì)應(yīng)的任期編號(hào)將為 2。
- 計(jì)數(shù)器,就是具體標(biāo)識(shí)提案的整數(shù),需要注意的是,每次領(lǐng)導(dǎo)者創(chuàng)建新的提案時(shí),計(jì)數(shù)器將遞增。比如,前一個(gè)提案對(duì)應(yīng)的計(jì)數(shù)器值為 1,那么新的提案對(duì)應(yīng)的計(jì)數(shù)器值將為 2。
????????為什么要設(shè)計(jì)的這么復(fù)雜呢?因?yàn)槭聞?wù)標(biāo)識(shí)符必須按照順序、唯一標(biāo)識(shí)一個(gè)提案,也就是說(shuō),事務(wù)標(biāo)識(shí)符必須是唯一的、遞增的。
????????在創(chuàng)建完提案之后,主節(jié)點(diǎn)會(huì)基于 TCP 協(xié)議,并按照順序?qū)⑻岚笍V播到其他節(jié)點(diǎn)。這樣就能保證先發(fā)送的消息,會(huì)先被收到,保證了消息接收的順序性。
????????然后,當(dāng)主節(jié)點(diǎn)接收到指定提案的“大多數(shù)”的確認(rèn)響應(yīng)后,該提案將處于提交狀態(tài)(Committed),主節(jié)點(diǎn)會(huì)通知備份節(jié)點(diǎn)提交該提案。
????????需要注意的是,主節(jié)點(diǎn)提交提案是有順序性的。主節(jié)點(diǎn)根據(jù)事務(wù)標(biāo)識(shí)符大小,按照順序提交提案,如果前一個(gè)提案未提交,此時(shí)主節(jié)點(diǎn)是不會(huì)提交后一個(gè)提案的。也就是說(shuō),指令 X 一定會(huì)在指令 Y 之前提交。????????
????????最后,主節(jié)點(diǎn)返回執(zhí)行成功的響應(yīng)給節(jié)點(diǎn) B,節(jié)點(diǎn) B 再轉(zhuǎn)發(fā)給客戶端。你看,這樣我們就實(shí)現(xiàn)了操作的順序性,保證了指令 X 一定在指令 Y 之前執(zhí)行。
????????當(dāng)寫(xiě)操作執(zhí)行完后,接下來(lái)可能需要執(zhí)行讀操作了。需要注意,為了提升讀并發(fā)能力,Zookeeper 提供的是最終一致性,也就是讀操作可以在任何節(jié)點(diǎn)上執(zhí)行,客戶端會(huì)讀到舊數(shù)據(jù):????????
????????如果客戶端必須要讀到最新數(shù)據(jù),怎么辦呢?Zookeeper 提供了一個(gè)解決辦法,那就是 sync 命令??梢栽趫?zhí)行讀操作前,先執(zhí)行 sync 命令,這樣客戶端就能讀到最新數(shù)據(jù)了。
? ? ? ? 2.2 領(lǐng)導(dǎo)者選舉
????????系統(tǒng)在運(yùn)行中,不可避免會(huì)出現(xiàn)各種各樣的問(wèn)題,比如進(jìn)程崩潰了、服務(wù)器死機(jī)了,這些問(wèn)題會(huì)導(dǎo)致很嚴(yán)重的后果,讓系統(tǒng)沒(méi)辦法運(yùn)行。在 ZAB 中,寫(xiě)請(qǐng)求是必須在主節(jié)點(diǎn)上處理的,而且提案的廣播和提交,也是由主節(jié)點(diǎn)來(lái)完成的。既然主節(jié)點(diǎn)那么重要,如果它突然崩潰宕機(jī)了,該怎么辦呢?答案是選舉出新的領(lǐng)導(dǎo)者(也就是新的主節(jié)點(diǎn))。
? ? ? ? 成員身份
????????既然要選舉領(lǐng)導(dǎo)者,那就涉及成員身份變更,那么在 ZAB 中,支持哪些成員身份呢。ZAB 支持 3 種成員身份(領(lǐng)導(dǎo)者、跟隨者、觀察者)。
- 領(lǐng)導(dǎo)者(Leader):作為主節(jié)點(diǎn)(Primary),在同一時(shí)間集群只會(huì)有一個(gè)領(lǐng)導(dǎo)者,所有的寫(xiě)請(qǐng)求必須在主節(jié)點(diǎn)上進(jìn)行。
- 跟隨者(Follower):作為備份節(jié)點(diǎn)(Backup),集群中可以有多個(gè)跟隨者,它們會(huì)響應(yīng)領(lǐng)導(dǎo)者的心跳,并參與領(lǐng)導(dǎo)者選舉和提案提交的投票。跟隨者可以直接處理并相應(yīng)客戶端的讀請(qǐng)求,但寫(xiě)請(qǐng)求必須轉(zhuǎn)發(fā)給領(lǐng)導(dǎo)者。
- 觀察者(Observer):作為備份節(jié)點(diǎn)(BackUp),類似跟隨者,但是沒(méi)有投票權(quán),不參與領(lǐng)導(dǎo)者選舉和提案提交的投票。
? ? ? ? 成員狀態(tài)
????????雖然 ZAB 支持 3 種成員身份,但是它定義了 4 種成員狀態(tài)。
- LOOKING:選舉狀態(tài),該狀態(tài)下的節(jié)點(diǎn)認(rèn)為當(dāng)前集群中沒(méi)有領(lǐng)導(dǎo)者,會(huì)發(fā)起領(lǐng)導(dǎo)者選舉。
- FOLLOWING :跟隨者狀態(tài),意味著當(dāng)前節(jié)點(diǎn)是跟隨者。
- LEADING :領(lǐng)導(dǎo)者狀態(tài),意味著當(dāng)前節(jié)點(diǎn)是領(lǐng)導(dǎo)者。
- OBSERVING: 觀察者狀態(tài),意味著當(dāng)前節(jié)點(diǎn)是觀察者。
????????為什么多了一種成員狀態(tài)呢?這是因?yàn)?ZAB 支持領(lǐng)導(dǎo)者選舉,在選舉過(guò)程中,涉及了一個(gè)過(guò)渡狀態(tài)(也就是選舉狀態(tài))。
? ? ? ? 領(lǐng)導(dǎo)者選舉
????????為了幫你更好地理解 ZAB 的領(lǐng)導(dǎo)者選舉,舉個(gè)例子演示一下,為了演示方便和更容易理解(我們聚焦最核心的領(lǐng)導(dǎo)者 PK),假設(shè)投票信息的格式是 <proposedLeader,?proposedEpoch,?proposedLastZxid,?node>,其中:
- proposedLeader:領(lǐng)導(dǎo)者的集群 ID,也就是在集群配置(比如 myid 配置文件)時(shí)指定的 ID。
- proposedEpoch:領(lǐng)導(dǎo)者的任期編號(hào)。
- proposedLastZxid:領(lǐng)導(dǎo)者的事務(wù)標(biāo)識(shí)符最大值(也就是最新提案的事務(wù)標(biāo)識(shí)符)。
- node:投票的節(jié)點(diǎn),比如節(jié)點(diǎn) B。
????????假設(shè)一個(gè) ZooKeeper 集群,由節(jié)點(diǎn) A、B、C 組成,其中節(jié)點(diǎn) A 是領(lǐng)導(dǎo)者,節(jié)點(diǎn) B、C 是跟隨者(為了方便演示,假設(shè) epoch 分別是 1 和 1,lastZxid 分別是 101 和 102,集群 ID 分別為 2 和 3)。那么如果節(jié)點(diǎn) A 宕機(jī)了,會(huì)如何選舉呢?
????????首先,當(dāng)跟隨者檢測(cè)到連接領(lǐng)導(dǎo)者節(jié)點(diǎn)的讀操作等待超時(shí)了,跟隨者會(huì)變更節(jié)點(diǎn)狀態(tài),將自己的節(jié)點(diǎn)狀態(tài)變更成 LOOKING,然后發(fā)起領(lǐng)導(dǎo)者選舉(假設(shè)這時(shí)節(jié)點(diǎn) B、C 都已經(jīng)檢測(cè)到了讀操作超時(shí)):
????????接著,每個(gè)節(jié)點(diǎn)會(huì)創(chuàng)建一張選票,這張選票是投給自己的,也就是說(shuō),節(jié)點(diǎn) B、C 都“自告奮勇”推薦自己為領(lǐng)導(dǎo)者,并創(chuàng)建選票 <2, 1, 101, B> 和 <3, 1, 102, C>,然后各自將選票發(fā)送給集群中所有節(jié)點(diǎn),也就是說(shuō),B 發(fā)送給 B、C,C 也發(fā)送給 B、C。
????????一般而言,節(jié)點(diǎn)會(huì)先接收到自己發(fā)送給自己的選票(因?yàn)椴恍枰绻?jié)點(diǎn)通訊,傳輸更快),也就是說(shuō),B 會(huì)先收到來(lái)自 B 的選票,C 會(huì)先收到來(lái)自 C 的選票:
????????集群的各節(jié)點(diǎn)收到選票后,為了選舉出數(shù)據(jù)最完整的節(jié)點(diǎn),對(duì)于每一張接收到選票,節(jié)點(diǎn)都需要進(jìn)行領(lǐng)導(dǎo)者 PK,也就將選票提議的領(lǐng)導(dǎo)者和自己提議的領(lǐng)導(dǎo)者進(jìn)行比較,找出更適合作為領(lǐng)導(dǎo)者的節(jié)點(diǎn),約定的規(guī)則如下:?
- 優(yōu)先檢查任期編號(hào)(Epoch),任期編號(hào)大的節(jié)點(diǎn)作為領(lǐng)導(dǎo)者;
- 如果任期編號(hào)相同,比較事務(wù)標(biāo)識(shí)符的最大值,值大的節(jié)點(diǎn)作為領(lǐng)導(dǎo)者;
- 如果事務(wù)標(biāo)識(shí)符的最大值相同,比較集群 ID,集群 ID 大的節(jié)點(diǎn)作為領(lǐng)導(dǎo)者。
????????如果選票提議的領(lǐng)導(dǎo)者,比自己提議的領(lǐng)導(dǎo)者,更適合作為領(lǐng)導(dǎo)者,那么節(jié)點(diǎn)將調(diào)整選票內(nèi)容,推薦選票提議的領(lǐng)導(dǎo)者作為領(lǐng)導(dǎo)者。
????????當(dāng)節(jié)點(diǎn) B、C 接收到的選票后,因?yàn)檫x票提議的領(lǐng)導(dǎo)者與自己提議的領(lǐng)導(dǎo)者相同,所以,領(lǐng)導(dǎo)者 PK 的結(jié)果,是不需要調(diào)整選票信息,那么節(jié)點(diǎn) B、C,正常接收和保存選票就可以了。
????????接著節(jié)點(diǎn) B、C 分別接收到來(lái)自對(duì)方的選票,比如 B 接收到來(lái)自 C 的選票,C 接收到來(lái)自 B 的選票。對(duì)于 C 而言,它提議的領(lǐng)導(dǎo)者是 C,而選票(<2, 1, 101, B>)提議的領(lǐng)導(dǎo)者是 B,因?yàn)楣?jié)點(diǎn) C 的任期編號(hào)與節(jié)點(diǎn) B 相同,但節(jié)點(diǎn) C 的事務(wù)標(biāo)識(shí)符的最大值比節(jié)點(diǎn) B 的大,那么,按照約定的規(guī)則,相比節(jié)點(diǎn) B,節(jié)點(diǎn) C 更適合作為領(lǐng)導(dǎo)者,也就是說(shuō),節(jié)點(diǎn) C 不需要調(diào)整選票信息,正常接收和保存選票就可以了。
????????接著,當(dāng)節(jié)點(diǎn) B、C 接收到來(lái)自節(jié)點(diǎn) B,新的選票時(shí),因?yàn)檫@張選票(<3, 1, 102, B>)提議的領(lǐng)導(dǎo)者,與他們提議的領(lǐng)導(dǎo)者是一樣的,都是節(jié)點(diǎn) C,所以,他們正常接收和存儲(chǔ)這張選票,就可以。
????????最后,因?yàn)榇藭r(shí)節(jié)點(diǎn) B、C 提議的領(lǐng)導(dǎo)者(節(jié)點(diǎn) C)贏得大多數(shù)選票了(2 張選票),那么,節(jié)點(diǎn) B、C 將根據(jù)投票結(jié)果,變更節(jié)點(diǎn)狀態(tài),并退出選舉。比如,因?yàn)楫?dāng)選的領(lǐng)導(dǎo)者是節(jié)點(diǎn) C,那么節(jié)點(diǎn) B 將變更狀態(tài)為 FOLLOWING,并退出選舉,而節(jié)點(diǎn) C 將變更狀態(tài)為 LEADING,并退出選舉。
? ? ? ? 到此,領(lǐng)導(dǎo)者選舉結(jié)束。
三、總結(jié)
????????總之,ZAB 協(xié)議是 ZooKeeper 實(shí)現(xiàn)其作為分布式協(xié)調(diào)服務(wù)核心功能的關(guān)鍵所在,確保了在復(fù)雜網(wǎng)絡(luò)環(huán)境和機(jī)器故障情況下,仍能提供強(qiáng)大而一致的數(shù)據(jù)服務(wù),支撐起眾多分布式系統(tǒng)的協(xié)同工作。
往期經(jīng)典推薦
探索分布式強(qiáng)一致性?shī)W秘:Paxos共識(shí)算法的精妙之旅-CSDN博客
Raft共識(shí)算法領(lǐng)導(dǎo)者選舉流程揭秘-CSDN博客
Redis使用規(guī)范的最佳實(shí)踐:打造高性能與穩(wěn)定性的關(guān)鍵法則-CSDN博客
SpringBoot項(xiàng)目并發(fā)處理大揭秘,你知道它到底能應(yīng)對(duì)多少請(qǐng)求洪峰?_springboot并發(fā)處理-CSDN博客文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-847120.html
Kafka消息流轉(zhuǎn)的挑戰(zhàn)與對(duì)策:消息丟失與重復(fù)消費(fèi)問(wèn)題_kafka發(fā)送消息生產(chǎn)者關(guān)閉了-CSDN博客文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-847120.html
到了這里,關(guān)于ZooKeeper是如何保證數(shù)據(jù)一致性的?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!