網(wǎng)站程序前臺/西安百度競價托管公司
分布式協(xié)調(diào)技術(shù)
在學(xué)習(xí)ZooKeeper之前需要先了解一種技術(shù)——分布式協(xié)調(diào)技術(shù)。那么什么是分布式協(xié)調(diào)技術(shù)?其實(shí)分布式協(xié)調(diào)技術(shù)主要用來解決分布式環(huán)境當(dāng)中多個進(jìn)程之間的同步控制,讓他們有序的去訪問某種臨界資源,防止造成"臟數(shù)據(jù)"的后果。這時,有人可能會說這個簡單,寫一個調(diào)度算法就輕松解決了。說這句話的人,可能對分布式系統(tǒng)不是很了解,所以才會出現(xiàn)這種誤解。如果這些進(jìn)程全部是跑在一臺機(jī)上的話,相對來說確實(shí)就好辦了,問 題就在于他是在一個分布式的環(huán)境下,這時問題又來了,那什么是分布式呢?可以通過下面這張圖幫助大家理解這方面的內(nèi)容,如下圖所示。
給大家分析一下這張圖,在這圖中有三臺機(jī)器,每臺機(jī)器各跑一個應(yīng)用程序。然后我們將這三臺機(jī)器通過網(wǎng)絡(luò)將其連接起來,構(gòu)成一個系統(tǒng)來為用戶提供服務(wù),對用戶來說這個系統(tǒng)的架構(gòu)是透明的,他感覺不到我這個系統(tǒng)是一個什么樣的架構(gòu)。那么我們就可以把這種系統(tǒng)稱作一個分布式系統(tǒng)。
那我們接下來再分析一下,在這個分布式系統(tǒng)中如何對進(jìn)程進(jìn)行調(diào)度,我假設(shè)在第一臺機(jī)器上掛載了一個資源,然后這三個物理分布的進(jìn)程都要競爭這個資源,但我們又不希望他們同時進(jìn)行訪問,這時候我們就需要一個協(xié)調(diào)器,來讓他們有序的來訪問這個資源。這個協(xié)調(diào)器就是我們經(jīng)常提到的那個鎖,比如說"進(jìn)程A"在使用該資源的時候,會先去獲得鎖,"進(jìn)程A"獲得鎖以后會對該資源保持獨(dú)占,這樣其他進(jìn)程就無法訪問該資源,"進(jìn)程A"用完該資源以后就將鎖釋放掉,讓其他進(jìn)程來獲得鎖,那么通過這個鎖機(jī)制,我們就能保證了分布式系統(tǒng)中多個進(jìn)程能夠有序的訪問該臨界資源。那么我們把這個分布式環(huán)境下的這個鎖叫作分布式鎖。這個分布式鎖也就是我們分布式協(xié)調(diào)技術(shù)實(shí)現(xiàn)的核心內(nèi)容,那么如何實(shí)現(xiàn)這個分布式呢,那就是我們后面要講的內(nèi)容。
分布式鎖的實(shí)現(xiàn)
面臨的問題
在看了上圖所示的分布式環(huán)境之后,有人可能會感覺這不是很難。無非是將原來在同一臺機(jī)器上對進(jìn)程調(diào)度的原語,通過網(wǎng)絡(luò)實(shí)現(xiàn)在分布式環(huán)境中。是的,表面上是可以這么說。但是問題就在網(wǎng)絡(luò)這,在分布式系統(tǒng)中,所有在同一臺機(jī)器上的假設(shè)都不存在:因為網(wǎng)絡(luò)是不可靠的。
比如,在同一臺機(jī)器上,你對一個服務(wù)的調(diào)用如果成功,那就是成功,如果調(diào)用失敗,比如拋出異常那就是調(diào)用失敗。但是在分布式環(huán)境中,由于網(wǎng)絡(luò)的不可靠,你對一個服務(wù)的調(diào)用失敗了并不表示一定是失敗的,可能是執(zhí)行成功了,但是響應(yīng)返回的時候失敗了。還有,A和B都去調(diào)用C服務(wù),在時間上 A還先調(diào)用一些,B后調(diào)用,那么最后的結(jié)果是不是一定A的請求就先于B到達(dá)呢? 這些在同一臺機(jī)器上的種種假設(shè),我們都要重新思考,我們還要思考這些問題給我們的設(shè)計和編碼帶來了哪些影響。還有,在分布式環(huán)境中為了提升可靠性,我們往往會部署多套服務(wù),但是如何在多套服務(wù)中達(dá)到一致性,這在同一臺機(jī)器上多個進(jìn)程之間的同步相對來說比較容易辦到,但在分布式環(huán)境中確實(shí)一個大難題。
所以分布式協(xié)調(diào)遠(yuǎn)比在同一臺機(jī)器上對多個進(jìn)程的調(diào)度要難得多,而且如果為每一個分布式應(yīng)用都開發(fā)一個獨(dú)立的協(xié)調(diào)程序。一方面,協(xié)調(diào)程序的反復(fù)編寫浪費(fèi),且難以形成通用、伸縮性好的協(xié)調(diào)器。另一方面,協(xié)調(diào)程序開銷比較大,會影響系統(tǒng)原有的性能。所以,急需一種高可靠、高可用的通用協(xié)調(diào)機(jī)制來用以協(xié)調(diào)分布式應(yīng)用。
分布式鎖的實(shí)現(xiàn)者
目前,在分布式協(xié)調(diào)技術(shù)方面做得比較好的就是Google的Chubby還有Apache的ZooKeeper他們都是分布式鎖的實(shí)現(xiàn)者。有人會問既然有了Chubby為什么還要弄一個ZooKeeper,難道Chubby做得不夠好嗎?不是這樣的,主要是Chbby是非開源的,Google自家用。后來雅虎模仿Chubby開發(fā)出了ZooKeeper,也實(shí)現(xiàn)了類似的分布式鎖的功能,并且將ZooKeeper作為一種開源的程序捐獻(xiàn)給了Apache,那么這樣就可以使用ZooKeeper所提供鎖服務(wù)。而且在分布式領(lǐng)域久經(jīng)考驗,它的可靠性,可用性都是經(jīng)過理論和實(shí)踐的驗證的。所以我們在構(gòu)建一些分布式系統(tǒng)的時候,就可以以這類系統(tǒng)為起點(diǎn)來構(gòu)建我們的系統(tǒng),這將節(jié)省不少成本,而且bug也 將更少。
Zookeeper介紹
ZooKeeper 是分布式應(yīng)用程序的分布式開源協(xié)調(diào)服務(wù)。它公開了一組簡單的原語,分布式應(yīng)用程序可以基于這些原語實(shí)現(xiàn)更高級別的同步、配置維護(hù)、組和命名服務(wù)等。它被設(shè)計為易于編程,并使用一種數(shù)據(jù)模型,該模型以熟悉的文件系統(tǒng)目錄樹結(jié)構(gòu)為風(fēng)格。它在 Java 中運(yùn)行,并具有 Java 和 C 的綁定。眾所周知,協(xié)調(diào)服務(wù)很難做好。它們特別容易出現(xiàn)競爭條件和死鎖等錯誤。ZooKeeper背后的動機(jī)是減輕分布式應(yīng)用程序從頭開始實(shí)現(xiàn)協(xié)調(diào)服務(wù)的責(zé)任。
設(shè)計目標(biāo)
ZooKeeper 很簡單。ZooKeeper 允許分布式進(jìn)程通過共享的分層命名空間相互協(xié)調(diào),該命名空間的組織方式類似于標(biāo)準(zhǔn)文件系統(tǒng)。命名空間由數(shù)據(jù)寄存器組成——在 ZooKeeper 用語中稱為 znodes——它們類似于文件和目錄。然后在該數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上定義了一些原語,也就是一些關(guān)于該數(shù)據(jù)結(jié)構(gòu)的一些操作。有了這些數(shù)據(jù)結(jié)構(gòu)和原語還不夠,因為我們的ZooKeeper是工作在一個分布式的環(huán)境下,我們的服務(wù)是通過消息以網(wǎng)絡(luò)的形式發(fā)送給我們的分布式應(yīng)用程序,所以還需要一個通知機(jī)制——Watcher機(jī)制。綜上,ZooKeeper所提供的服務(wù)主要是通過:數(shù)據(jù)結(jié)構(gòu)+原語+watcher機(jī)制,三個部分來實(shí)現(xiàn)的。與為存儲而設(shè)計的典型文件系統(tǒng)不同,ZooKeeper 數(shù)據(jù)保存在內(nèi)存中,這意味著 ZooKeeper 可以實(shí)現(xiàn)高吞吐量和低延遲數(shù)字。
ZooKeeper 實(shí)施非常重視高性能、高可用性、嚴(yán)格有序的訪問。ZooKeeper 的性能方面意味著它可以用于大型分布式系統(tǒng)。可靠性方面使其不會成為單點(diǎn)故障。嚴(yán)格的排序意味著可以在客戶端實(shí)現(xiàn)復(fù)雜的同步原語。
ZooKeeper 被復(fù)制。與它協(xié)調(diào)的分布式進(jìn)程一樣,ZooKeeper 本身旨在通過一組稱為 ensemble 的主機(jī)進(jìn)行復(fù)制。
組成 ZooKeeper 服務(wù)的服務(wù)器必須相互了解。它們在內(nèi)存中維護(hù)狀態(tài)圖像,以及持久存儲中的事務(wù)日志和快照。只要大多數(shù)服務(wù)器可用,ZooKeeper 服務(wù)就可用。
客戶端連接到單個 ZooKeeper 服務(wù)器??蛻舳司S護(hù)一個 TCP 連接,通過它發(fā)送請求、獲取響應(yīng)、獲取監(jiān)視事件并發(fā)送心跳。如果與服務(wù)器的 TCP 連接中斷,客戶端將連接到不同的服務(wù)器。
ZooKeeper 已訂購。ZooKeeper 使用反映所有 ZooKeeper 事務(wù)順序的數(shù)字標(biāo)記每個更新。后續(xù)操作可以使用該順序來實(shí)現(xiàn)更高級別的抽象,例如同步原語。
ZooKeeper 速度很快。它在“以讀取為主”的工作負(fù)載中尤其快。ZooKeeper 應(yīng)用程序在數(shù)千臺機(jī)器上運(yùn)行,它在讀取比寫入更常見的情況下表現(xiàn)最佳,比率約為 10:1。
zookeeper數(shù)據(jù)模型和分層命名空間
ZooKeeper 提供的命名空間很像標(biāo)準(zhǔn)文件系統(tǒng)。名稱是由斜杠 (/) 分隔的一系列路徑元素。ZooKeeper 命名空間中的每個節(jié)點(diǎn)都由路徑標(biāo)識。
從上圖中我們可以看出ZooKeeper的數(shù)據(jù)模型,在結(jié)構(gòu)上和標(biāo)準(zhǔn)文件系統(tǒng)的非常相似,都是采用這種樹形層次結(jié)構(gòu),ZooKeeper樹中的每個節(jié)點(diǎn)被稱為—Znode。和文件系統(tǒng)的目錄樹一樣,ZooKeeper樹中的每個節(jié)點(diǎn)可以擁有子節(jié)點(diǎn)。但也有不同之處:
(1) 引用方式
Zonde通過路徑引用,如同Unix中的文件路徑。路徑必須是絕對的,因此他們必須由斜杠字符來開頭。除此以外,他們必須是唯一的,也就是說每一個路徑只有一個表示,因此這些路徑不能改變。在ZooKeeper中,路徑由Unicode字符串組成,并且有一些限制。字符串"/zookeeper"用以保存管理信息,比如關(guān)鍵配額信息。
(2) Znode結(jié)構(gòu)
ZooKeeper命名空間中的Znode,兼具文件和目錄兩種特點(diǎn)。既像文件一樣維護(hù)著數(shù)據(jù)、元信息、ACL、時間戳等數(shù)據(jù)結(jié)構(gòu),又像目錄一樣可以作為路徑標(biāo)識的一部分。圖中的每個節(jié)點(diǎn)稱為一個Znode。 每個Znode由3部分組成:
?、?stat:此為狀態(tài)信息, 描述該Znode的版本, 權(quán)限等信息
?、?data:與該Znode關(guān)聯(lián)的數(shù)據(jù)
③ children:該Znode下的子節(jié)點(diǎn)
ZooKeeper雖然可以關(guān)聯(lián)一些數(shù)據(jù),但并沒有被設(shè)計為常規(guī)的數(shù)據(jù)庫或者大數(shù)據(jù)存儲,相反的是,它用來管理調(diào)度數(shù)據(jù),比如分布式應(yīng)用中的配置文件信息、狀態(tài)信息、匯集位置等等。這些數(shù)據(jù)的共同特性就是它們都是很小的數(shù)據(jù),通常以KB為大小單位。ZooKeeper的服務(wù)器和客戶端都被設(shè)計為嚴(yán)格檢查并限制每個Znode的數(shù)據(jù)大小至多1M,但常規(guī)使用中應(yīng)該遠(yuǎn)小于此值。
(3) 數(shù)據(jù)訪問
ZooKeeper中的每個節(jié)點(diǎn)存儲的數(shù)據(jù)要被原子性的操作。也就是說讀操作將獲取與節(jié)點(diǎn)相關(guān)的所有數(shù)據(jù),寫操作也將替換掉節(jié)點(diǎn)的所有數(shù)據(jù)。另外,每一個節(jié)點(diǎn)都擁有自己的ACL(訪問控制列表),這個列表規(guī)定了用戶的權(quán)限,即限定了特定用戶對目標(biāo)節(jié)點(diǎn)可以執(zhí)行的操作。
(4) 節(jié)點(diǎn)類型
ZooKeeper中的節(jié)點(diǎn)有兩種,分別為臨時節(jié)點(diǎn)和永久節(jié)點(diǎn)。節(jié)點(diǎn)的類型在創(chuàng)建時即被確定,并且不能改變。
?、?臨時節(jié)點(diǎn):該節(jié)點(diǎn)的生命周期依賴于創(chuàng)建它們的會話。一旦會話(Session)結(jié)束,臨時節(jié)點(diǎn)將被自動刪除,當(dāng)然可以也可以手動刪除。雖然每個臨時的Znode都會綁定到一個客戶端會話,但他們對所有的客戶端還是可見的。另外,ZooKeeper的臨時節(jié)點(diǎn)不允許擁有子節(jié)點(diǎn)。
② 永久節(jié)點(diǎn):該節(jié)點(diǎn)的生命周期不依賴于會話,并且只有在客戶端顯示執(zhí)行刪除操作的時候,他們才能被刪除。
(5) 順序節(jié)點(diǎn)
當(dāng)創(chuàng)建Znode的時候,用戶可以請求在ZooKeeper的路徑結(jié)尾添加一個遞增的計數(shù)。這個計數(shù)對于此節(jié)點(diǎn)的父節(jié)點(diǎn)來說是唯一的,它的格式為"%10d"(10位數(shù)字,沒有數(shù)值的數(shù)位用0補(bǔ)充,例如"0000000001")。當(dāng)計數(shù)值大于232-1時,計數(shù)器將溢出。
(6) 觀察
客戶端可以在節(jié)點(diǎn)上設(shè)置watch,我們稱之為監(jiān)視器。當(dāng)節(jié)點(diǎn)狀態(tài)發(fā)生改變時(Znode的增、刪、改)將會觸發(fā)watch所對應(yīng)的操作。當(dāng)watch被觸發(fā)時,ZooKeeper將會向客戶端發(fā)送且僅發(fā)送一條通知,因為watch只能被觸發(fā)一次,這樣可以減少網(wǎng)絡(luò)流量。
3.6.0 中的新功能:客戶端還可以在 znode 上設(shè)置永久的遞歸監(jiān)??視,這些監(jiān)視在觸發(fā)時不會被刪除,并且會以遞歸方式觸發(fā)已注冊 znode 以及任何子 znode 上的更改。
ZooKeeper中的時間
致使ZooKeeper節(jié)點(diǎn)狀態(tài)改變的每一個操作都將使節(jié)點(diǎn)接收到一個Zxid格式的時間戳,并且這個時間戳全局有序。也就是說,每個對節(jié)點(diǎn)的改變都將產(chǎn)生一個唯一的Zxid。如果Zxid1的值小于Zxid2的值,那么Zxid1所對應(yīng)的事件發(fā)生在Zxid2所對應(yīng)的事件之前。實(shí)際上,ZooKeeper的每個節(jié)點(diǎn)維護(hù)者三個Zxid值,為別為:cZxid、mZxid、pZxid。
① cZxid: 是節(jié)點(diǎn)的創(chuàng)建時間所對應(yīng)的Zxid格式時間戳。
② mZxid:是節(jié)點(diǎn)的修改時間所對應(yīng)的Zxid格式時間戳。
③ pZxid: 是與該節(jié)點(diǎn)的子節(jié)點(diǎn)(或該節(jié)點(diǎn))的最近一次 創(chuàng)建/刪除 的時間戳對應(yīng)
實(shí)現(xiàn)中Zxid是一個64為的數(shù)字,它高32位是epoch用來標(biāo)識leader關(guān)系是否改變,每次一個leader被選出來,它都會有一個 新的epoch。低32位是個遞增計數(shù)版本號
對節(jié)點(diǎn)的每一個操作都將致使這個節(jié)點(diǎn)的版本號增加。每個節(jié)點(diǎn)維護(hù)著三個版本號,他們分別為:
① version:節(jié)點(diǎn)數(shù)據(jù)版本號
② cversion:子節(jié)點(diǎn)版本號
③ aversion:節(jié)點(diǎn)所擁有的ACL版本號
ZooKeeper節(jié)點(diǎn)屬性
通過前面的介紹,我們可以了解到,一個節(jié)點(diǎn)自身擁有表示其狀態(tài)的許多重要屬性,如下圖所示。
Znode節(jié)點(diǎn)屬性結(jié)構(gòu)
屬性 | 描述 |
---|---|
czxid | 節(jié)點(diǎn)被創(chuàng)建的zxid |
mzxid | 節(jié)點(diǎn)被修改的zxid . |
ctime | 節(jié)點(diǎn)被創(chuàng)建的時間 |
mtime | 節(jié)點(diǎn)被修改的zxid |
version | 節(jié)點(diǎn)被修改的版本號 |
cversion | 節(jié)點(diǎn)所擁有的子節(jié)點(diǎn)被修改的版本號 |
aversion | 節(jié)點(diǎn)的ACL被修改的版本號 |
ephemeralowner | 如果此節(jié)點(diǎn)為臨時節(jié)點(diǎn),那么他的值為這個節(jié)點(diǎn)擁有者的會話ID;否則,他的值為0 |
dataLength | 節(jié)點(diǎn)數(shù)長度 |
numChildren | 節(jié)點(diǎn)用的子節(jié)點(diǎn)長度 |
pzxid | 最新修改的zxid,貌似與mzxid重合了 |
ZooKeeper中的數(shù)據(jù)保證
ZooKeeper 非??焖偾曳浅:唵?。但是,由于它的目標(biāo)是成為構(gòu)建更復(fù)雜服務(wù)(例如同步)的基礎(chǔ),因此它提供了一組保證。這些都是:
- 順序一致性 - 來自客戶端的更新將按照它們發(fā)送的順序應(yīng)用。
- 原子性 - 更新成功或失敗。沒有部分結(jié)果。
- 單一系統(tǒng)映像 - 客戶端將看到相同的服務(wù)視圖,而不管它連接到的服務(wù)器如何。即,即使客戶端故障轉(zhuǎn)移到具有相同會話的不同服務(wù)器,客戶端也永遠(yuǎn)不會看到系統(tǒng)的舊視圖。
- 可靠性 - 應(yīng)用更新后,它將從那時起持續(xù)存在,直到客戶端覆蓋更新。
- 及時性——系統(tǒng)的客戶視圖保證在一定的時間范圍內(nèi)是最新的。
zookeeper簡單的 API操作
ZooKeeper 的設(shè)計目標(biāo)之一是提供一個非常簡單的編程接口。因此,它僅支持以下操作:
create:在樹中的某個位置創(chuàng)建一個節(jié)點(diǎn)
delete : 刪除一個節(jié)點(diǎn)
exists:測試節(jié)點(diǎn)是否存在于某個位置
getACL:獲取數(shù)據(jù),從節(jié)點(diǎn)讀取數(shù)據(jù)
setACL:設(shè)置數(shù)據(jù),將數(shù)據(jù)寫入節(jié)點(diǎn)
getChildren :獲取子節(jié)點(diǎn):檢索節(jié)點(diǎn)的子節(jié)點(diǎn)列表
sync:等待數(shù)據(jù)傳播
執(zhí)行
ZooKeeper 組件展示了 ZooKeeper 服務(wù)的高級組件。除了請求處理器之外,組成 ZooKeeper 服務(wù)的每個服務(wù)器都復(fù)制自己的每個組件的副本。
復(fù)制數(shù)據(jù)庫是包含整個數(shù)據(jù)樹的內(nèi)存數(shù)據(jù)庫。更新被記錄到磁盤以便恢復(fù),寫入在應(yīng)用到內(nèi)存數(shù)據(jù)庫之前被序列化到磁盤。
每個 ZooKeeper 服務(wù)器都服務(wù)于客戶端??蛻舳藘H連接到一臺服務(wù)器以提交請求。從每個服務(wù)器數(shù)據(jù)庫的本地副本為讀取請求提供服務(wù)。改變服務(wù)狀態(tài)的請求,寫請求,由協(xié)議協(xié)議處理。
作為協(xié)議協(xié)議的一部分,來自客戶端的所有寫入請求都被轉(zhuǎn)發(fā)到單個服務(wù)器,稱為領(lǐng)導(dǎo)者。ZooKeeper 服務(wù)器的其余部分,稱為追隨者,接收來自領(lǐng)導(dǎo)者的消息提議并同意消息傳遞。消息傳遞層負(fù)責(zé)在失敗時替換領(lǐng)導(dǎo)者并將追隨者與領(lǐng)導(dǎo)者同步。
ZooKeeper 使用自定義原子消息傳遞協(xié)議。由于消息傳遞層是原子的,ZooKeeper 可以保證本地副本永遠(yuǎn)不會發(fā)散。當(dāng)領(lǐng)導(dǎo)者收到一個寫請求時,它會計算系統(tǒng)在應(yīng)用寫時的狀態(tài),并將其轉(zhuǎn)換為捕獲這個新狀態(tài)的事務(wù)。
用途
ZooKeeper 的編程接口故意簡單。但是,使用它,您可以實(shí)現(xiàn)更高階的操作,例如同步原語、組成員資格、所有權(quán)等。
ZooKeeper應(yīng)用實(shí)例
為了方便大家理解ZooKeeper,用以下例子說明ZooKeeper是如何實(shí)現(xiàn)的他的服務(wù)的,以ZooKeeper提供的基本服務(wù)分布式鎖為例。
分布式鎖應(yīng)用場景
在分布式鎖服務(wù)中,有一種最典型應(yīng)用場景,就是通過對集群進(jìn)行Master選舉,來解決分布式系統(tǒng)中的單點(diǎn)故障。什么是分布式系統(tǒng)中的單點(diǎn)故障:通常分布式系統(tǒng)采用主從模式,就是一個主控機(jī)連接多個處理節(jié)點(diǎn)。主節(jié)點(diǎn)負(fù)責(zé)分發(fā)任務(wù),從節(jié)點(diǎn)負(fù)責(zé)處理任務(wù),當(dāng)我們的主節(jié)點(diǎn)發(fā)生故障時,那么整個系統(tǒng)就都癱瘓了,那么我們把這種故障叫作單點(diǎn)故障。如下圖所示:
傳統(tǒng)解決方案
傳統(tǒng)方式是采用一個備用節(jié)點(diǎn),這個備用節(jié)點(diǎn)定期給當(dāng)前主節(jié)點(diǎn)發(fā)送ping包,主節(jié)點(diǎn)收到ping包以后向備用節(jié)點(diǎn)發(fā)送回復(fù)Ack,當(dāng)備用節(jié)點(diǎn)收到回復(fù)的時候就會認(rèn)為當(dāng)前主節(jié)點(diǎn)還活著,讓他繼續(xù)提供服務(wù)。如下圖所示:
而當(dāng)主節(jié)點(diǎn)掛了,這時候備用節(jié)點(diǎn)收不到回復(fù)了,然后他就認(rèn)為主節(jié)點(diǎn)掛了接替他成為主節(jié)點(diǎn)。如下圖所示:
但是這種方式就是有一個隱患,就是網(wǎng)絡(luò)問題,來看一網(wǎng)絡(luò)問題會造成什么后果,如下圖7.5所示:
也就是說我們的主節(jié)點(diǎn)的并沒有掛,只是在回復(fù)的時候網(wǎng)絡(luò)發(fā)生故障,這樣我們的備用節(jié)點(diǎn)同樣收不到回復(fù),就會認(rèn)為主節(jié)點(diǎn)掛了,然后備用節(jié)點(diǎn)將他的Master實(shí)例啟動起來,這樣我們的分布式系統(tǒng)當(dāng)中就有了兩個主節(jié)點(diǎn)也就是雙Master,出現(xiàn)Master以后我們的從節(jié)點(diǎn)就會將它所做的事一部分匯報給了主節(jié)點(diǎn),一部分匯報給了從節(jié)點(diǎn),這樣服務(wù)就全亂了。為了防止出現(xiàn)這種情況,我們引入了ZooKeeper,它雖然不能避免網(wǎng)絡(luò)故障,但它能夠保證每時每刻只有一個Master。下面來看一下ZooKeeper是如何實(shí)現(xiàn)的。
ZooKeeper解決方案
Master啟動
在引入了Zookeeper以后我們啟動了兩個主節(jié)點(diǎn),“主節(jié)點(diǎn)-A"和"主節(jié)點(diǎn)-B"他們啟動以后,都向ZooKeeper去注冊一個節(jié)點(diǎn)。我們假設(shè)"主節(jié)點(diǎn)-A"鎖注冊地節(jié)點(diǎn)是"master-00001”,“主節(jié)點(diǎn)-B"注冊的節(jié)點(diǎn)是"master-00002”,注冊完以后進(jìn)行選舉,編號最小的節(jié)點(diǎn)將在選舉中獲勝獲得鎖成為主節(jié)點(diǎn),也就是我們的"主節(jié)點(diǎn)-A"將會獲得鎖成為主節(jié)點(diǎn),然后"主節(jié)點(diǎn)-B"將被阻塞成為一個備用節(jié)點(diǎn)。那么,通過這種方式就完成了對兩個Master進(jìn)程的調(diào)度。
Master故障
如果"主節(jié)點(diǎn)-A"掛了,這時候他所注冊的節(jié)點(diǎn)將被自動刪除,ZooKeeper會自動感知節(jié)點(diǎn)的變化,然后再次發(fā)出選舉,這時候"主節(jié)點(diǎn)-B"將在選舉中獲勝,替代"主節(jié)點(diǎn)-A"成為主節(jié)點(diǎn)。
Master 恢復(fù)
如果主節(jié)點(diǎn)恢復(fù)了,他會再次向ZooKeeper注冊一個節(jié)點(diǎn),這時候他注冊的節(jié)點(diǎn)將會是"master-00003",ZooKeeper會感知節(jié)點(diǎn)的變化再次發(fā)動選舉,這時候"主節(jié)點(diǎn)-B"在選舉中會再次獲勝繼續(xù)擔(dān)任"主節(jié)點(diǎn)","主節(jié)點(diǎn)-A"會擔(dān)任備用節(jié)點(diǎn)。
更多關(guān)于zookeeper的知識分享,請前往博客主頁。編寫過程中,難免出現(xiàn)差錯,敬請指出