此文知識(shí)來自于:《從Paxos到Zookeeper分布式一致性原理與實(shí)踐》第六章
- 集群管理(子節(jié)點(diǎn))
- Master選舉(同時(shí)創(chuàng)建節(jié)點(diǎn))
- 分布式鎖(同時(shí)創(chuàng)建節(jié)點(diǎn))
- 分布式隊(duì)列(創(chuàng)建順序節(jié)點(diǎn))
5.1 集群管理
隨著分布式系統(tǒng)規(guī)模的日益擴(kuò)大瀑踢,集群中的機(jī)器規(guī)模也隨之變大沽一,因此瞪浸,如何更好地進(jìn)行集群管理也顯得越來越重要了什燕。
所謂集群管理,包括集群監(jiān)控與集群控制兩大塊揭糕、前者側(cè)重對(duì)集群運(yùn)行時(shí)狀態(tài)的收集萝快,后者則是對(duì)集群進(jìn)行操作與控制。在日常開發(fā)和運(yùn)維過程中著角,我們經(jīng)常會(huì)有
類似于如下的需求揪漩。
- 希望知道當(dāng)前集群中究竟有多少機(jī)器在工作。
- 對(duì)集群中每臺(tái)機(jī)器的運(yùn)行時(shí)狀態(tài)進(jìn)行數(shù)據(jù)收集吏口。
- 對(duì)集群中機(jī)器進(jìn)行上下線操作奄容。
在傳統(tǒng)的基于Agent的分布式集群管理體系中,都是通過在集群中的每臺(tái)機(jī)器上部署一個(gè)Agent产徊,由這個(gè)Agent負(fù)責(zé)主動(dòng)向指定的一個(gè)監(jiān)控中心系統(tǒng)(監(jiān)控中心
系統(tǒng)負(fù)責(zé)將所有數(shù)據(jù)進(jìn)行集中處理昂勒,形成一系列報(bào)表舟铜,并負(fù)責(zé)實(shí)時(shí)報(bào)警戈盈,以下簡(jiǎn)稱“監(jiān)控中心”)匯報(bào)自己所在機(jī)器的狀態(tài)。在集群規(guī)模適中的場(chǎng)景下谆刨,這確實(shí)
是一種在生產(chǎn)實(shí)踐中廣泛使用的解決方案塘娶,能夠快速有效地實(shí)現(xiàn)分布式環(huán)境集群監(jiān)控,但是一旦系統(tǒng)的業(yè)務(wù)場(chǎng)景增多痊夭,集群規(guī)模變大刁岸,該解決方案的弊端也就顯現(xiàn)出來了:
- 大規(guī)模升級(jí)困難:以客戶端形式存在的Agent,在大規(guī)模使用后她我,一旦遇到需要大規(guī)模升級(jí)的情況难捌,就非常麻煩膝宁,在升級(jí)成本和升級(jí)進(jìn)度的控制上面臨巨大的挑戰(zhàn)鸦难。
- 統(tǒng)一的Agent無法滿足多樣的需求:對(duì)于機(jī)器的CPU使用率根吁、負(fù)載(Load)、內(nèi)存使用率合蔽、網(wǎng)絡(luò)吞吐以及磁盤容量等機(jī)器基本的物理狀態(tài)击敌,使用統(tǒng)一的Agent
來進(jìn)行監(jiān)控或許都可以滿足。但是拴事,如果需要深入應(yīng)用內(nèi)部沃斤,對(duì)一些業(yè)務(wù)狀態(tài)進(jìn)行監(jiān)控,例如刃宵,在一個(gè)分布式消息中間件中衡瓶,希望監(jiān)控到每個(gè)消費(fèi)者對(duì)消息的消費(fèi)狀態(tài);
或者在一個(gè)分布式任務(wù)調(diào)度系統(tǒng)中牲证,需要對(duì)每個(gè)機(jī)器上任務(wù)的執(zhí)行情況進(jìn)行監(jiān)控哮针。很顯然,對(duì)于這些業(yè)務(wù)耦合緊密的監(jiān)控需求坦袍,不適合由一個(gè)統(tǒng)一的Agent來提供十厢。 - 編程語(yǔ)言多樣性:隨著越來越多編程語(yǔ)言的出現(xiàn),各種異構(gòu)系統(tǒng)層出不窮捂齐。如果使用傳統(tǒng)的Agent方式蛮放,那么需要提供各種語(yǔ)言的Agent客戶端。另一方面奠宜,
“監(jiān)控中心”在對(duì)異構(gòu)系統(tǒng)的數(shù)據(jù)進(jìn)行整合上面臨巨大挑戰(zhàn)包颁。
ZooKeeper具有以下兩大特性:
- 客戶端如果對(duì)ZooKeeper的一個(gè)數(shù)據(jù)節(jié)點(diǎn)注冊(cè)Watcher監(jiān)聽,那么當(dāng)該數(shù)據(jù)節(jié)點(diǎn)的內(nèi)容或是其子節(jié)點(diǎn)列表發(fā)生變更時(shí)压真,ZooKeeper服務(wù)器就會(huì)向訂閱的
客戶端發(fā)送變更通知娩嚼。 - 對(duì)在ZooKeeper上創(chuàng)建的臨時(shí)節(jié)點(diǎn),一旦客戶端與服務(wù)器之間的會(huì)話失效榴都,那么該臨時(shí)節(jié)點(diǎn)也就被自動(dòng)清除待锈。
利用ZooKeeper的這兩大特性,就可以實(shí)現(xiàn)另一種集群機(jī)器存活性監(jiān)控的系統(tǒng)嘴高。例如竿音,監(jiān)控系統(tǒng)在/clusterServers
節(jié)點(diǎn)上注冊(cè)一個(gè)Watcher監(jiān)聽,
那么但凡進(jìn)行動(dòng)態(tài)添加機(jī)器的操作拴驮,就會(huì)在/clusterServers
節(jié)點(diǎn)下創(chuàng)建一個(gè)臨時(shí)節(jié)點(diǎn)/clusterServers/[Hostname]
春瞬。這樣一來監(jiān)控系統(tǒng)就能夠?qū)崟r(shí)
檢測(cè)到機(jī)器的變動(dòng)情況,至于后續(xù)處理就是監(jiān)控系統(tǒng)的業(yè)務(wù)了套啤。下面我們就通過分布式日志收集系統(tǒng)和在線云主機(jī)管理這兩個(gè)典型例子來看看如何使用ZooKeeper
實(shí)現(xiàn)集群管理宽气。
5.1.1 分布式日志收集系統(tǒng)
分布式日志收集系統(tǒng)的核心工作就是收集分布在不同機(jī)器上的系統(tǒng)日志随常,在這里我們重點(diǎn)來看分布式日志系統(tǒng)的收集器模塊。
在一個(gè)典型的日志系統(tǒng)的架構(gòu)設(shè)計(jì)中萄涯,整個(gè)日志系統(tǒng)會(huì)把所有需要收集的日志機(jī)器(下文以“日志源機(jī)器”代表此類機(jī)器)分為多個(gè)組別绪氛,每個(gè)組別對(duì)應(yīng)一個(gè)收集器,
這個(gè)收集器其實(shí)就是一個(gè)后臺(tái)機(jī)器(下文以“收集器機(jī)器”代表此類機(jī)器)涝影,用于收集日志枣察。對(duì)于大規(guī)模的分布式日志收集系統(tǒng)場(chǎng)景,通常需要解決如下兩個(gè)問題燃逻。
- 變化的日志源機(jī)器:在生產(chǎn)環(huán)境中序目,伴隨著機(jī)器的變動(dòng),每個(gè)應(yīng)用的機(jī)器幾乎每天都是在變化的(機(jī)器硬件問題伯襟、擴(kuò)容猿涨、機(jī)房遷移或是網(wǎng)絡(luò)問題都會(huì)導(dǎo)致一個(gè)應(yīng)用的機(jī)器變化),
也就是說每個(gè)組別中的日志源機(jī)器通常是在不斷變化的姆怪。 - 變化的收集器機(jī)器:日志收集系統(tǒng)自身也會(huì)有機(jī)器的變更或擴(kuò)容叛赚,于是會(huì)出現(xiàn)新的收集器加入或是老的收集器機(jī)器退出的情況。
上面兩個(gè)問題片效,無論是日志源機(jī)器還是收集器機(jī)器的變更红伦,最終都?xì)w結(jié)為一點(diǎn):如何快速、合理淀衣、動(dòng)態(tài)地為每個(gè)收集器分配對(duì)應(yīng)的日志源機(jī)器昙读,這也成為了整個(gè)
日志系統(tǒng)正確穩(wěn)定運(yùn)轉(zhuǎn)的前提,也是日志收集過程中最大的技術(shù)挑戰(zhàn)膨桥。在這種情況下蛮浑,引入ZooKeeper是個(gè)不錯(cuò)的選擇,下面我們來看ZooKeeper在這個(gè)
場(chǎng)景中的使用只嚣。
.1 注冊(cè)收集器機(jī)器
使用ZooKeeper來進(jìn)行日志系統(tǒng)收集器的注冊(cè)沮稚、典型做法是在ZooKeeper上創(chuàng)建一個(gè)節(jié)點(diǎn)作為收集器的根節(jié)點(diǎn),例如/logs/collector
(下文我們以“收集器
節(jié)點(diǎn)”代表該數(shù)據(jù)節(jié)點(diǎn))册舞,每個(gè)收集器機(jī)器在啟動(dòng)的時(shí)候蕴掏,都會(huì)在收集器節(jié)點(diǎn)下創(chuàng)建自己的節(jié)點(diǎn),例如logs/collector/[Hostname]
调鲸。
.2 任務(wù)分發(fā)
待所有收集器機(jī)器都創(chuàng)建好自己對(duì)應(yīng)的節(jié)點(diǎn)后盛杰,系統(tǒng)根據(jù)收集器節(jié)點(diǎn)下子節(jié)點(diǎn)的個(gè)數(shù),將所有日志源機(jī)器分成對(duì)應(yīng)的若干組藐石,然后將分組后的機(jī)器列表分別寫到
這些收集器機(jī)器創(chuàng)建的子節(jié)點(diǎn)(例如/logs/collector/host1
)上去即供。這樣一來,每個(gè)收集器機(jī)器都能夠從自己對(duì)應(yīng)的收集器節(jié)點(diǎn)獲取日志源機(jī)器列表于微,
進(jìn)而開始進(jìn)行日志收集工作逗嫡。
.3 狀態(tài)匯報(bào)
完成收集器機(jī)器的注冊(cè)以及任務(wù)分發(fā)后青自,我們還要考慮到這些機(jī)器隨時(shí)都有掛掉的可能。因此驱证,針對(duì)這個(gè)問題延窜,我們需要有一個(gè)收集器的狀態(tài)匯報(bào)機(jī)制:
每個(gè)收集器機(jī)器在創(chuàng)建完自己的專屬節(jié)點(diǎn)后,還需要在對(duì)應(yīng)的子節(jié)點(diǎn)上創(chuàng)建一個(gè)狀態(tài)子節(jié)點(diǎn)雷滚,例如/logs/collector/host1/status
需曾,每個(gè)收集器都需要定期向
該節(jié)點(diǎn)寫入自己的狀態(tài)信息。我們可以把這種策略看作是一種檢測(cè)機(jī)制祈远,通常收集器機(jī)器都會(huì)在這個(gè)節(jié)點(diǎn)寫入日志收集進(jìn)度信息。日志系統(tǒng)根據(jù)該狀態(tài)子節(jié)點(diǎn)的最后更新時(shí)間
來判斷對(duì)應(yīng)的收集器機(jī)器是否存活商源。
.4 動(dòng)態(tài)分配
如果收集器機(jī)器掛掉或是擴(kuò)容了车份,就需要?jiǎng)討B(tài)地進(jìn)行收集任務(wù)的分配。在運(yùn)行過程中牡彻,日志系統(tǒng)始終關(guān)注著/logs/collector
這個(gè)節(jié)點(diǎn)下所有子節(jié)點(diǎn)的變更扫沼,
一旦檢測(cè)到有收集器機(jī)器停止匯報(bào)或是有新的收集器機(jī)器加入,就要開始進(jìn)行任務(wù)的重新分配庄吼。無論是針對(duì)收集器機(jī)器停止匯報(bào)還是新機(jī)器加入的情況缎除,
日志系統(tǒng)都需要將之前分配給該收集器的所有任務(wù)轉(zhuǎn)移。為了解決這個(gè)問題总寻,通常有兩種做法器罐。
.4.1 全局動(dòng)態(tài)分配
這是一種簡(jiǎn)單粗暴的做法,在出現(xiàn)收集器機(jī)器掛掉或是新機(jī)器加入的時(shí)候渐行,日志系統(tǒng)需要根據(jù)新的收集器機(jī)器列表轰坊,立即對(duì)所有的日志源機(jī)器重新進(jìn)行一次分組,
然后將其分配給剩下的收集器機(jī)器祟印。
.4.2 局部動(dòng)態(tài)分配
全局動(dòng)態(tài)分配方式雖然策略簡(jiǎn)單肴沫,但是存在一個(gè)問題:一個(gè)或部分收集器機(jī)器的變更,就會(huì)導(dǎo)致全局動(dòng)態(tài)任務(wù)的分配蕴忆,影響面比較大颤芬,因此風(fēng)險(xiǎn)也就比較大。
所謂局部動(dòng)態(tài)分配套鹅,顧名思義就是在小范圍內(nèi)進(jìn)行任務(wù)的動(dòng)態(tài)分配站蝠。在這種策略中,每個(gè)收集器機(jī)器在匯報(bào)自己日志收集狀態(tài)的同時(shí)芋哭,也會(huì)把自己的負(fù)載匯報(bào)上去沉衣。
請(qǐng)注意减牺,這里提到的負(fù)載并不僅僅只是簡(jiǎn)單地指機(jī)器CPU負(fù)載(Load)豌习,而是一個(gè)對(duì)當(dāng)前收集器任務(wù)執(zhí)行的綜合評(píng)估既荚。
在這種策略中,如果一個(gè)收集器機(jī)器掛了矾屯,那么日志系統(tǒng)就會(huì)把之前分配給這個(gè)機(jī)器的任務(wù)重新分配到那些負(fù)載較低的機(jī)器上去哈雏。同樣,如果有新的收集器機(jī)器加入虱黄,
會(huì)從那些負(fù)載高的機(jī)器上轉(zhuǎn)移部分任務(wù)給這個(gè)新加入的機(jī)器宗挥。
.5 注意事項(xiàng)
.5.1 節(jié)點(diǎn)類型
首先看/logs/collector
這個(gè)節(jié)點(diǎn)下面子節(jié)點(diǎn)的節(jié)點(diǎn)類型。這個(gè)節(jié)點(diǎn)下面的所有子節(jié)點(diǎn)都代表了每個(gè)收集器機(jī)器古毛,那么初步認(rèn)為這些子節(jié)點(diǎn)必須選擇臨時(shí)節(jié)點(diǎn),
原因是日志系統(tǒng)可以根據(jù)這些臨時(shí)節(jié)點(diǎn)來判斷收集器機(jī)器的存活性馍刮。但是,同時(shí)還需要注意的一點(diǎn)是:在分布式日志收集這個(gè)場(chǎng)景中,收集器節(jié)點(diǎn)上還會(huì)存放所有
已經(jīng)分配給該收集器機(jī)器的日志源機(jī)器列表薇芝,如果只是簡(jiǎn)單地依靠ZooKeeper自身的臨時(shí)節(jié)點(diǎn)機(jī)制,那么當(dāng)一個(gè)收集器掛掉或是當(dāng)這個(gè)收集器機(jī)器中斷“心跳匯報(bào)”
的時(shí)候瀑粥,待該收集器節(jié)點(diǎn)的會(huì)話失效后剂府,ZooKeeper就會(huì)立即刪除該節(jié)點(diǎn),于是,記錄在該節(jié)點(diǎn)上的所有日志源機(jī)器列表也就隨之被清除掉了饱亿。
從上面的描述中可以知道蚜退,臨時(shí)節(jié)點(diǎn)顯然無法滿足這里的業(yè)務(wù)需求,所以我們選擇了使用持久節(jié)點(diǎn)來標(biāo)識(shí)每一個(gè)收集器機(jī)器彪笼,同時(shí)在這個(gè)持久節(jié)點(diǎn)下面分別創(chuàng)建
/logs/collector/[Hostname]/status
節(jié)點(diǎn)來表征每一個(gè)收集器機(jī)器的狀態(tài)钻注。這樣一來缓艳,既能實(shí)現(xiàn)日志系統(tǒng)對(duì)所有收集器的監(jiān)控浅蚪,同時(shí)在收集器機(jī)器掛掉
后讯蒲,依然能夠準(zhǔn)確地將分配于其中的任務(wù)還原来庭。
.5.2 日志系統(tǒng)節(jié)點(diǎn)監(jiān)聽
在實(shí)際生產(chǎn)運(yùn)行過程中摹芙,每一個(gè)收集器機(jī)器更改自己狀態(tài)節(jié)點(diǎn)的頻率可能非常高(如每秒1次或更短)驮吱,而且收集器的數(shù)量可能非常大阳距,如果日志系統(tǒng)監(jiān)聽所有
這些節(jié)點(diǎn)變化逾雄,那么通知的消息量可能會(huì)非常大腐巢。另一方面品追,在收集器機(jī)器正常工作的情況下,日志系統(tǒng)沒有必要去實(shí)時(shí)地接收每次節(jié)點(diǎn)狀態(tài)變更系忙,因此大部分
這些變更通知都是無用的诵盼。因此我們考慮放棄監(jiān)聽設(shè)置,而是采用日志系統(tǒng)主動(dòng)輪詢收集器節(jié)點(diǎn)的策略,這樣就節(jié)省了不少網(wǎng)卡流量风宁,唯一的缺陷就是有
一定的延時(shí)(考慮到分布式日志收集系統(tǒng)的定位洁墙,這個(gè)延時(shí)是可以接受的)。
5.1.2 在線云主機(jī)管理
在線云主機(jī)管理通常出現(xiàn)在那些虛擬主機(jī)提供商的應(yīng)用場(chǎng)景中戒财。在這類集群管理中热监,有很重要的一塊就是集群機(jī)器的監(jiān)控。這個(gè)場(chǎng)景通常對(duì)于集群中的機(jī)器狀態(tài)饮寞,
尤其是機(jī)器在線率的統(tǒng)計(jì)有較高的要求孝扛,同時(shí)需要能夠快速地對(duì)集群中機(jī)器的變更做出響應(yīng)。
在傳統(tǒng)的實(shí)現(xiàn)方案中幽崩,監(jiān)控系統(tǒng)通過某種手段(比如檢測(cè)主機(jī)的指定端口)來對(duì)每臺(tái)機(jī)器進(jìn)行定時(shí)檢測(cè)苦始,或者每臺(tái)機(jī)器自己定時(shí)向監(jiān)控系統(tǒng)匯報(bào)“我還活著”。
但是這種方式需要每個(gè)業(yè)務(wù)系統(tǒng)的開發(fā)人員自己來處理網(wǎng)絡(luò)通信慌申、協(xié)議設(shè)計(jì)陌选、調(diào)度和容災(zāi)等諸多瑣碎的問題。下面來看看使用ZooKeeper實(shí)現(xiàn)的另一種集群機(jī)器
存活性監(jiān)控系統(tǒng)蹄溉。針對(duì)這個(gè)系統(tǒng)咨油,我們的需求點(diǎn)通常如下。
- 如何快速地統(tǒng)計(jì)當(dāng)前生產(chǎn)環(huán)境一共有多少臺(tái)機(jī)器柒爵?
- 如何快速地獲取到機(jī)器上/下線的情況役电?
- 如何實(shí)時(shí)監(jiān)控集群中每臺(tái)主機(jī)的運(yùn)行時(shí)狀態(tài)?
.1 機(jī)器上/下線
為了實(shí)現(xiàn)自動(dòng)化的線上運(yùn)維棉胀,我們必須對(duì)機(jī)器的上/下線情況有一個(gè)全局的監(jiān)控法瑟。通常在新增機(jī)器的時(shí)候,需要首先將指定的Agent部署到這些機(jī)器上去唁奢。
Agent部署啟動(dòng)之后瓢谢,會(huì)首先向ZooKeeper的指定節(jié)點(diǎn)進(jìn)行注冊(cè),具體的做法就是在機(jī)器列表節(jié)點(diǎn)下面創(chuàng)建一個(gè)臨時(shí)子節(jié)點(diǎn)驮瞧,例如/XAE/machine/[Hostname]
(下文以“主機(jī)節(jié)點(diǎn)”代表這個(gè)節(jié)點(diǎn)),如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-12.png)
當(dāng)Agent在ZooKeeper上創(chuàng)建完這個(gè)臨時(shí)子節(jié)點(diǎn)后枯芬,對(duì)
/XAE/machines
節(jié)點(diǎn)關(guān)注的監(jiān)控中心就會(huì)接收到“子節(jié)點(diǎn)變更”事件论笔,即上線通知,于是就可以對(duì)這個(gè)新加入的機(jī)器開啟相應(yīng)的后臺(tái)管理邏輯千所。另一方面狂魔,監(jiān)控中心同樣可以獲取到機(jī)器下線的通知,這樣便實(shí)現(xiàn)了對(duì)機(jī)器上/下線的檢測(cè)淫痰,同時(shí)能夠很容易地獲取
到在線的機(jī)器列表最楷,對(duì)于大規(guī)模的擴(kuò)容和容量評(píng)估都有很大的幫助。
.2 機(jī)器監(jiān)控
對(duì)于一個(gè)在線云主機(jī)系統(tǒng),不僅要對(duì)機(jī)器的在線狀態(tài)進(jìn)行檢測(cè)籽孙,還需要對(duì)機(jī)器的運(yùn)行時(shí)狀態(tài)進(jìn)行監(jiān)控烈评。在運(yùn)行的過程中,Agent會(huì)定時(shí)將主機(jī)的運(yùn)行狀態(tài)信息
寫入ZooKeeper上的主機(jī)節(jié)點(diǎn)犯建,監(jiān)控中心通過訂閱這些節(jié)點(diǎn)的數(shù)據(jù)變更通知來間接地獲取主機(jī)的運(yùn)行時(shí)信息讲冠。
隨著分布式系統(tǒng)規(guī)模變得越來越龐大,對(duì)集群機(jī)器的監(jiān)控和管理顯得越來越重要适瓦。上面提到的這種借助ZooKeeper來實(shí)現(xiàn)的方式竿开,不僅能夠?qū)崟r(shí)地檢測(cè)到集群
中機(jī)器的上/下線情況,而且能夠?qū)崟r(shí)地獲取到主機(jī)的運(yùn)行時(shí)信息玻熙,從而能夠構(gòu)建出一個(gè)大規(guī)模集群的主機(jī)圖譜否彩。
6.1 Master選舉
Master選舉是一個(gè)在分布式系統(tǒng)中非常常見的應(yīng)用場(chǎng)景。分布式最核心的特性就是能夠?qū)⒕哂歇?dú)立計(jì)算能力的系統(tǒng)單元部署在不同的機(jī)器上嗦随,構(gòu)成一個(gè)完整的
分布式系統(tǒng)列荔。而與此同時(shí),實(shí)際場(chǎng)景中往往也需要在這些分布在不同機(jī)器上的獨(dú)立系統(tǒng)單元中選出一個(gè)所謂的“老大”称杨,在計(jì)算機(jī)科學(xué)中肌毅,我們稱之為“Master”。
在分布式系統(tǒng)中姑原,Master往往用來協(xié)調(diào)集群中其他系統(tǒng)單元悬而,具有對(duì)分布式系統(tǒng)狀態(tài)變更的決定權(quán)。例如锭汛,在一些讀寫分離的應(yīng)用場(chǎng)景中笨奠,客戶端的寫請(qǐng)求往往
是由Master來處理的;而在另一些場(chǎng)景中唤殴,Master則常常負(fù)責(zé)處理一些復(fù)雜的邏輯般婆,并將處理結(jié)果同步給集群中其它系統(tǒng)單元。Master選舉可以說是ZooKeeper
最典型的應(yīng)用場(chǎng)景了朵逝,在本節(jié)中蔚袍,我們就結(jié)合“一種海量數(shù)據(jù)處理與共享模型”這個(gè)具體例子來看看ZooKeeper在集群Master選舉中的應(yīng)用場(chǎng)景。
在分布式環(huán)境中配名,經(jīng)常會(huì)碰到這樣的應(yīng)用場(chǎng)景:集群中的所有系統(tǒng)單元需要對(duì)前端業(yè)務(wù)提供數(shù)據(jù)啤咽,比如一個(gè)商品ID,或者是一個(gè)網(wǎng)站輪播廣告的廣告ID(通常
出現(xiàn)在一些廣告投放系統(tǒng)中)等渠脉,而這些商品ID或是廣告ID往往需要從一系列的海量數(shù)據(jù)處理中計(jì)算得到————這通常是一個(gè)非常耗費(fèi)I/O和CPU資源的過程宇整。
鑒于該計(jì)算過程的復(fù)雜性,如果讓集群中的所有機(jī)器都執(zhí)行這個(gè)計(jì)算邏輯的話芋膘,那么將耗費(fèi)非常多的資源鳞青。一種比較好的方法就是只讓集群中的部分霸饲,甚至只
讓其中的一臺(tái)機(jī)器去處理數(shù)據(jù)計(jì)算,一旦計(jì)算出數(shù)據(jù)結(jié)果臂拓,就可以共享給整個(gè)集群中的其他所有客戶端機(jī)器厚脉,這樣可以大大減少重復(fù)勞動(dòng),提升性能埃儿。
這里我們以一個(gè)簡(jiǎn)單的廣告投放系統(tǒng)后臺(tái)場(chǎng)景為例來講解這個(gè)模型器仗。整個(gè)系統(tǒng)大體上可以分成客戶端集群、分布式緩存系統(tǒng)童番、海量數(shù)據(jù)處理總線和ZooKeeper
四個(gè)部分精钮,如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-13.png)
Client集群每天定時(shí)會(huì)通過ZooKeeper來實(shí)現(xiàn)Master選舉。選舉產(chǎn)生Master客戶端之后剃斧,這個(gè)Master就會(huì)負(fù)責(zé)進(jìn)行一系列的海量數(shù)據(jù)處理轨香,最終計(jì)算得到
一個(gè)數(shù)據(jù)結(jié)果,并將其放置在一個(gè)內(nèi)存/數(shù)據(jù)庫(kù)中幼东。同時(shí)臂容,Master還需要通知集群中其它所有的客戶端從這個(gè)內(nèi)存/數(shù)據(jù)庫(kù)中共享計(jì)算結(jié)果。
接下去根蟹,我們將重點(diǎn)來看Master選舉的過程脓杉,首先來明確下Master選舉的需求:在集群的所有機(jī)器中選舉出一臺(tái)機(jī)器作為Master。針對(duì)這個(gè)需求简逮,通常情況
下球散,我們可以選擇常見的關(guān)系型數(shù)據(jù)庫(kù)中的主鍵特性來實(shí)現(xiàn):集群中的所有機(jī)器都向數(shù)據(jù)庫(kù)中插入一條相同主鍵ID的記錄,數(shù)據(jù)庫(kù)會(huì)幫助我們自動(dòng)進(jìn)行主鍵沖突
檢查散庶,也就是說蕉堰,所有進(jìn)行插入操作的客戶端機(jī)器中,只有一臺(tái)機(jī)器能夠成功————那么悲龟,我們就認(rèn)為向數(shù)據(jù)庫(kù)中成功插入數(shù)據(jù)的客戶端機(jī)器成為Master屋讶。
乍一看,這個(gè)方案確實(shí)可行须教,依靠關(guān)系型數(shù)據(jù)庫(kù)的主鍵特性能夠很好地保證在集群中選舉出唯一的一個(gè)Master皿渗。但是我們需要考慮的另一個(gè)問題是,如果當(dāng)前
選舉出的Master掛了轻腺,那么該如何處理羹奉?誰來告訴我Master掛了呢?顯然约计,關(guān)系型數(shù)據(jù)庫(kù)沒法通知我們這個(gè)事件。
ZooKeeper的強(qiáng)一致性迁筛,能夠很好地保證在分布式高并發(fā)情況下節(jié)點(diǎn)的創(chuàng)建一定能夠保證全局唯一性煤蚌,即ZooKeeper將會(huì)保證客戶端無法重復(fù)創(chuàng)建一個(gè)已經(jīng)存在
的數(shù)據(jù)節(jié)點(diǎn)耕挨。也就是說,如果同時(shí)有多個(gè)客戶端請(qǐng)求創(chuàng)建同一個(gè)節(jié)點(diǎn)尉桩,那么最終一定只有一個(gè)客戶端請(qǐng)求能夠創(chuàng)建成功筒占。利用這個(gè)特性,就能很容易地在分布式
環(huán)境中進(jìn)行Master選舉了蜘犁。
在這個(gè)系統(tǒng)中翰苫,首先會(huì)在ZooKeeper上創(chuàng)建一個(gè)日期節(jié)點(diǎn),如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-14.png)
客戶端集群每天都會(huì)定時(shí)往ZooKeeper上創(chuàng)建一個(gè)臨時(shí)節(jié)點(diǎn)这橙,例如
/master_election/2017-09-03/binding
奏窑。在這個(gè)過程中,只有一個(gè)客戶端能夠成功創(chuàng)建這個(gè)節(jié)點(diǎn)屈扎,那么這個(gè)客戶端所在機(jī)器就稱為了Master埃唯。同時(shí),其他沒有在ZooKeeper上成功創(chuàng)建節(jié)點(diǎn)的客戶端鹰晨,都會(huì)在節(jié)點(diǎn)
/master_ecection/2017-09-03
上注冊(cè)一個(gè)子節(jié)點(diǎn)變更的Watcher墨叛,用于監(jiān)控當(dāng)前的Master機(jī)器是否存活,一旦發(fā)現(xiàn)當(dāng)前的Master掛了模蜡,那么其余的客戶端將會(huì)重新進(jìn)行Master選舉漠趁。
從上面的講解中,我們可以看到忍疾,如果僅僅只是想實(shí)現(xiàn)Master選舉的話闯传,那么其實(shí)只需要有一個(gè)能夠保證唯一性的組件即可,例如關(guān)系型數(shù)據(jù)庫(kù)的主鍵模型
就是不錯(cuò)的選擇膝昆。但是丸边,如果希望能夠快速地進(jìn)行集群Master動(dòng)態(tài)選舉,那么基于ZooKeeper來實(shí)現(xiàn)是一個(gè)不錯(cuò)的新思路荚孵。
7.1 分布式鎖
分布式鎖是控制分布式系統(tǒng)之間同步訪問共享資源的一種方式妹窖。如果不同的系統(tǒng)或是同一個(gè)系統(tǒng)的不同主機(jī)之間共享了一個(gè)或一組資源,那么訪問這些資源的
時(shí)候收叶,往往需要通過一些互斥手段來防止彼此之間的干擾骄呼,以保證一致性,在這種情況下判没,就需要使用分布式鎖了蜓萄。
在平時(shí)的實(shí)際項(xiàng)目開發(fā)中,我們往往很少會(huì)去在意分布式鎖澄峰,而是依賴于關(guān)系型數(shù)據(jù)庫(kù)固有的排他性來實(shí)現(xiàn)不同進(jìn)程之間的互斥嫉沽。這確實(shí)是一種非常簡(jiǎn)便且被
廣泛使用的分布式鎖實(shí)現(xiàn)方式。然而有一個(gè)不爭(zhēng)的事實(shí)是俏竞,目前絕大多數(shù)大型分布式系統(tǒng)的性能瓶頸都集中在數(shù)據(jù)庫(kù)操作上绸硕。因此,如果上層業(yè)務(wù)再給數(shù)據(jù)庫(kù)
添加一些額外的鎖玻佩,例如行鎖、表鎖甚至是繁重的事務(wù)處理咬崔,那么是不是會(huì)讓數(shù)據(jù)庫(kù)更加不堪重負(fù)呢?下面我們來看看使用ZooKeeper如何實(shí)現(xiàn)分布式鎖垮斯,
這里主要講解排他鎖和共享鎖兩類分布式鎖郎仆。
7.1.1 排他鎖
排他鎖(Exclusive Locks甚脉,簡(jiǎn)稱X鎖)丸升,又稱為寫鎖或獨(dú)占鎖牺氨,是一種基本的鎖類型狡耻。如果事務(wù)T1對(duì)數(shù)據(jù)對(duì)象O1加上了排他鎖,那么在整個(gè)加鎖期間猴凹,只允許
事務(wù)T1對(duì)O1進(jìn)行讀取和更新操作,其他任何事務(wù)都不能再對(duì)這個(gè)數(shù)據(jù)對(duì)象進(jìn)行任何類型的操作————直到T1釋放了排他鎖郊霎。
從上面講解的排他鎖的基本概念中,我們可以看到书劝,排他鎖的核心是如何保證當(dāng)前有且僅有一個(gè)事務(wù)獲得鎖,并且鎖被釋放后购对,所有正在等待獲取鎖的事務(wù)都
能夠被通知到。下面我們就看看如何借助ZooKeeper實(shí)現(xiàn)排他鎖骡苞。
.1 定義鎖
有兩種常見的方式可以用來定義鎖,分別是synchronized機(jī)制和JDK5提供的ReentrantLock解幽。然而,在ZooKeeper中躲株,沒有類似于這樣的API可以直接使用,
而是通過ZooKeeper上的數(shù)據(jù)節(jié)點(diǎn)來表示一個(gè)鎖霜定,例如/exclusive_lock/lock
節(jié)點(diǎn)就可以被定義為一個(gè)鎖捆探,如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-15.png)
.2 獲取鎖
在需要獲取排他鎖時(shí)站粟,所有的客戶端都會(huì)試圖通過調(diào)用create()接口,在/exclusive_lock
節(jié)點(diǎn)下創(chuàng)建臨時(shí)子節(jié)點(diǎn)/exclusive_lock/lock
奴烙。而ZooKeeper
會(huì)保證在所有的客戶端中,最終只有一個(gè)客戶端能夠創(chuàng)建成功切诀,那么就可以認(rèn)為該客戶端獲取了鎖搔弄。同時(shí)幅虑,所有沒有獲取到鎖的客戶端就需要到/exclusive_lock
節(jié)點(diǎn)上注冊(cè)一個(gè)子節(jié)點(diǎn)變更的Watcher監(jiān)聽顾犹,以便實(shí)時(shí)監(jiān)聽到lock節(jié)點(diǎn)的變更情況。
.3 釋放鎖
由于是臨時(shí)節(jié)點(diǎn)炫刷,有下面兩種情況,可能釋放鎖:
- 當(dāng)前獲取鎖的客戶端機(jī)器發(fā)生宕機(jī)
- 正常執(zhí)行完業(yè)務(wù)邏輯后浑玛,客戶端主動(dòng)將臨時(shí)節(jié)點(diǎn)刪除。
無論在上面情況下移除了lock節(jié)點(diǎn)顾彰,ZooKeeper都會(huì)通知所有在/exclusive_lock
節(jié)點(diǎn)上注冊(cè)了子節(jié)點(diǎn)變更Watcher監(jiān)聽的客戶端。這些客戶端在接收到通知后涨享,
再次重新發(fā)起分布式鎖獲取,即重復(fù)“獲取鎖”過程灰伟。如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-16.png)
7.1.2 共享鎖
共享鎖(Shared Locks,簡(jiǎn)稱S鎖)栏账,又稱讀鎖,同樣是一種基本的鎖類型挡爵。如果事務(wù)T1對(duì)數(shù)據(jù)對(duì)象O1加上了共享鎖,那么當(dāng)前事務(wù)只能對(duì)O1進(jìn)行讀取操作茶鹃,
其他事務(wù)也只能對(duì)這個(gè)數(shù)據(jù)對(duì)象加共享鎖————直到該數(shù)據(jù)對(duì)象上的所有共享鎖都被釋放。
共享鎖和排他鎖最根本的區(qū)別在于挣郭,加上排他鎖后,數(shù)據(jù)對(duì)象只對(duì)一個(gè)事務(wù)可見兑障,而加上共享鎖后,數(shù)據(jù)對(duì)所有事務(wù)都可見流译。
.1 定義鎖
和排他鎖一樣,同樣是通過ZooKeeper上的數(shù)據(jù)節(jié)點(diǎn)來表示一個(gè)鎖福澡,是一個(gè)類似于/shared_lock/[Hostname]-請(qǐng)求類型-序號(hào)
的臨時(shí)順序節(jié)點(diǎn),例如
/shared_lock/192.168.0.1-R-0000000001
革砸,那么,這個(gè)節(jié)點(diǎn)就代表了一個(gè)共享鎖业岁,如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-17.png)
.2 獲取鎖
在需要獲取共享鎖時(shí),所有客戶端都會(huì)到/shared_lock
這個(gè)節(jié)點(diǎn)下面創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn)笔时,如果當(dāng)前是讀請(qǐng)求,那么就創(chuàng)建例如/shared_lock/192.168.0.1-R-000000001/
的節(jié)點(diǎn)允耿;如果是寫請(qǐng)求,那么就創(chuàng)建例如/shared_lock/192.168.0.1-W-000000001
的節(jié)點(diǎn)较锡。
.3 判斷讀寫順序
根據(jù)共享鎖的定義,不同的事務(wù)都可以同時(shí)對(duì)同一數(shù)據(jù)對(duì)象進(jìn)行讀取操作蚂蕴,而更新操作必須在當(dāng)前沒有任何事務(wù)進(jìn)行讀寫操作的情況下進(jìn)行÷饴ィ基于這個(gè)原則,
我們來看看如何通過ZooKeeper的節(jié)點(diǎn)來確定分布式讀寫順序鸟整,大致可以分為如下4個(gè)步驟。
- 創(chuàng)建完節(jié)點(diǎn)后,獲取
/shared_lock
節(jié)點(diǎn)下的所有子節(jié)點(diǎn)弟头,并對(duì)該節(jié)點(diǎn)注冊(cè)子節(jié)點(diǎn)變更的Watcher監(jiān)聽。 - 確定自己的節(jié)點(diǎn)序號(hào)在所有子節(jié)點(diǎn)中的順序赴恨。
- 如果當(dāng)前節(jié)點(diǎn)業(yè)務(wù)為讀請(qǐng)求:如果沒有比自己序號(hào)小的子節(jié)點(diǎn),或是所有比自己序號(hào)小的子節(jié)點(diǎn)都是讀請(qǐng)求伦连,那么表明自己已經(jīng)成功獲取到了共享鎖,同時(shí)
開始執(zhí)行讀取邏輯。如果比自己序號(hào)小的子節(jié)點(diǎn)有寫請(qǐng)求扔枫,那么就需要進(jìn)入等待。
如果當(dāng)前節(jié)點(diǎn)業(yè)務(wù)為寫請(qǐng)求:如果自己不是序號(hào)最小的子節(jié)點(diǎn)短荐, 那么就需要進(jìn)入等待。 - 接收到Watcher通知后忍宋,重復(fù)步驟1。
.4 釋放鎖
釋放鎖的邏輯和排他鎖是一致的糠排。
.5 羊群效應(yīng)
上面講解的這個(gè)共享鎖實(shí)現(xiàn),大體上能夠滿足一般的分布式集群競(jìng)爭(zhēng)鎖的需求入宦,并且性能都還可以————這里說的一般場(chǎng)景是指集群規(guī)模不是特別大,一般是在
10臺(tái)機(jī)器以內(nèi)乾闰。但是如果機(jī)器規(guī)模擴(kuò)大之后,會(huì)有什么問題呢涯肩?我們著重來看上面“判斷讀寫順序”過程的步驟3,如下圖病苗,看看實(shí)際運(yùn)行中的情況。
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-18.png)
- 192.168.0.1這臺(tái)機(jī)器首先進(jìn)行讀操作继谚,完成讀操作后將節(jié)點(diǎn)
/192.168.0.1-R-000000001
刪除。 - 余下的4臺(tái)機(jī)器均收到了這個(gè)節(jié)點(diǎn)被移除的通知花履,然后重新從
/shared_lock/
節(jié)點(diǎn)上獲取一份新的子節(jié)點(diǎn)列表。 - 每個(gè)機(jī)器判斷自己的讀寫順序诡壁。其中192.168.0.2這臺(tái)機(jī)器檢測(cè)到自己已經(jīng)是序號(hào)最小的機(jī)器了,于是開始進(jìn)行寫操作妹卿,而余下的其他機(jī)器發(fā)現(xiàn)沒有輪到
自己進(jìn)行讀取或更新操作,于是繼續(xù)等待夺克。 - 繼續(xù)......
上面這個(gè)過程就是共享鎖在實(shí)際運(yùn)行中最主要的步驟了,我們著重看下上面步驟3中提到的:“而余下的其他機(jī)器發(fā)現(xiàn)沒有輪到自己進(jìn)行讀取或更新操作铺纽,于是繼續(xù)等待〗泼牛”
很明顯,我們看到其馏,192.168.0.1這個(gè)客戶端在移除自己的共享鎖后,ZooKeeper發(fā)送了子節(jié)點(diǎn)變更Watcher通知給所有機(jī)器仔引,然而這個(gè)通知除了給192.168.0.2
這臺(tái)機(jī)器產(chǎn)生實(shí)際影響外,對(duì)于余下的其他所有機(jī)器都沒有任何作用肤寝。
相信讀者也已經(jīng)意思到了,在這整個(gè)分布式鎖的競(jìng)爭(zhēng)過程中鲤看,大量的“Watcher通知”和“子節(jié)點(diǎn)列表獲取”兩個(gè)操作重復(fù)運(yùn)行,并且絕大多數(shù)的運(yùn)行結(jié)果都是
判斷出自己并非是序號(hào)最小的節(jié)點(diǎn)义桂,從而繼續(xù)等待下一次通知————這個(gè)看起來顯然不怎么科學(xué)蹈垢】兜酰客戶端無端地接收到過多和自己并不相關(guān)的事件通知曹抬,如果在集群
規(guī)模比較大的情況下,不僅會(huì)對(duì)ZooKeeper服務(wù)器造成巨大的性能影響和網(wǎng)絡(luò)沖擊,更為嚴(yán)重的是疾宏,如果同一時(shí)間有多個(gè)節(jié)點(diǎn)對(duì)應(yīng)的客戶端完成事務(wù)或是事務(wù)
中斷引起節(jié)點(diǎn)消息,ZooKeeper服務(wù)器就會(huì)在短時(shí)間內(nèi)向其余客戶端發(fā)送大量的事件通知————這就是所謂的羊群效應(yīng)坎藐。
上面這個(gè)ZooKeeper分布式共享鎖實(shí)現(xiàn)中出現(xiàn)羊群效應(yīng)的根源在于,沒有找準(zhǔn)客戶端真正的關(guān)注點(diǎn)岩馍。我們?cè)賮砘仡櫼幌律厦娴姆植际芥i競(jìng)爭(zhēng)過程抖韩,它和核心
邏輯在于:判斷自己是否是所有子節(jié)點(diǎn)中序號(hào)最小的蛀恩。于是茂浮,很容易可以聯(lián)想到,每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的客戶端只需要關(guān)注比自己序號(hào)小的那個(gè)相關(guān)節(jié)點(diǎn)的變更情況
就可以了————而不需要關(guān)注全局的子列表變更情況励稳。
.6 改進(jìn)后的分布式鎖實(shí)現(xiàn)
現(xiàn)在我們來看看如何改進(jìn)上面的分布式鎖實(shí)現(xiàn)囱井。首先,我們需要肯定的一點(diǎn)是庞呕,上面提到的共享鎖實(shí)現(xiàn),從整體思路上來說完全正確住练。這里主要的改動(dòng)在于:
每個(gè)鎖競(jìng)爭(zhēng)者,只需要關(guān)注/shared_lock/
節(jié)點(diǎn)下序號(hào)比自己小的那個(gè)節(jié)點(diǎn)是否存在即可讲逛,具體實(shí)現(xiàn)如下:
- 客戶端調(diào)用create()方法創(chuàng)建一個(gè)類似于
/shared_lock/[Hostname]-請(qǐng)求類型-序號(hào)
的臨時(shí)順序節(jié)點(diǎn)。 - 客戶端調(diào)用getChildren()接口來獲取所有已經(jīng)創(chuàng)建的子節(jié)點(diǎn)列表盏混,注意,這里不注冊(cè)任何Watcher许赃。
- 如果無法獲取共享鎖,那么就調(diào)用exist()來對(duì)比自己小的那個(gè)節(jié)點(diǎn)注冊(cè)Watcher混聊。注意弹谁,這里“比自己小的節(jié)點(diǎn)”只是一個(gè)籠統(tǒng)的說法,具體對(duì)于讀請(qǐng)求和寫請(qǐng)求不一樣预愤。
讀請(qǐng)求:向比自己序號(hào)小的最后一個(gè)寫請(qǐng)求節(jié)點(diǎn)注冊(cè)Watcher監(jiān)聽。
寫請(qǐng)求:向比自己序號(hào)小的最后一個(gè)節(jié)點(diǎn)注冊(cè)Watcher監(jiān)聽鳖粟。 - 等待Watcher通知,繼續(xù)進(jìn)入步驟2泳秀。
流程圖如下:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-19.png)
.7 注意
看到這里,相信很多讀者都會(huì)覺得改進(jìn)后的分布式鎖實(shí)現(xiàn)相對(duì)來說比較麻煩嗜傅。確實(shí)如此檩赢,如同在多線程并發(fā)編程實(shí)踐中吕嘀,我們會(huì)去盡量縮小鎖的范圍————對(duì)于
分布式鎖實(shí)現(xiàn)的改進(jìn)其實(shí)也是同樣的思路贞瞒。那么對(duì)于開發(fā)人員來說,是否必須按照改進(jìn)后的思路來設(shè)計(jì)實(shí)現(xiàn)自己的分布式鎖呢军浆?答案是否定的。在具體的實(shí)際開發(fā)
過程中乒融,我們提倡根據(jù)具體的業(yè)務(wù)場(chǎng)景和集群規(guī)模來選擇適合自己的分布式鎖實(shí)現(xiàn):在集群規(guī)模不大、網(wǎng)絡(luò)資源豐富的情況下赞季,第一種分布式鎖實(shí)現(xiàn)方式是
簡(jiǎn)單實(shí)用的選擇;而如果集群規(guī)模達(dá)到一定程度申钩,并且希望能夠精細(xì)化地控制分布式鎖機(jī)制,那么不妨試試改進(jìn)版的分布式鎖實(shí)現(xiàn)撒遣。
8.1 分布式隊(duì)列
業(yè)界有不少分布式隊(duì)列產(chǎn)品,不過絕大多數(shù)都是類似于ActiveMQ钢猛、Kafka等的消息中間件。在本節(jié)中命迈,我們主要介紹基于ZooKeeper實(shí)現(xiàn)的分布式隊(duì)列贩绕。
分布式隊(duì)列壶愤,簡(jiǎn)單地講分為兩大類,一種是常規(guī)的先入先出隊(duì)列征椒,另一種則是要等到隊(duì)列元素集聚之后才統(tǒng)一安排執(zhí)行的Barrier模型。
8.1.1 FIFO:先進(jìn)先出
使用ZooKeeper實(shí)現(xiàn)FIFO隊(duì)列勃救,和共享鎖的實(shí)現(xiàn)非常類似。FIFO隊(duì)列就類似于一個(gè)全寫的共享鎖模型蒙秒,大體的設(shè)計(jì)思想其實(shí)非常簡(jiǎn)單:所有客戶端都會(huì)到
/queue_fifo
這個(gè)節(jié)點(diǎn)下面創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn),例如/queue_fifo/192.168.0.1-0000000001
晕讲,如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-20.png)
創(chuàng)建完節(jié)點(diǎn)之后,根據(jù)如下4個(gè)步驟來確定執(zhí)行順序弄息。
- 通過調(diào)用getChildren()接口來獲取
/queue_fifo
節(jié)點(diǎn)下的所有子節(jié)點(diǎn),即獲取隊(duì)列中所有的元素摹量。 - 確定自己的節(jié)點(diǎn)序號(hào)在所有子節(jié)點(diǎn)中的順序。
- 如果自己不是序號(hào)最小的子節(jié)點(diǎn),那么就需要進(jìn)入等待废亭,同時(shí)向比自己序號(hào)小的最后一個(gè)節(jié)點(diǎn)注冊(cè)Watcher監(jiān)聽。
- 接收到Watcher通知到豆村,重復(fù)步驟1。
整個(gè)FIFO隊(duì)列的工作流程掌动,如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-21.png)
8.1.2 Barrier:分布式屏障
Barrier原意是指障礙物、屏障粗恢,而在分布式系統(tǒng)中,特指系統(tǒng)之間的一個(gè)協(xié)調(diào)條件匙赞,規(guī)定了一個(gè)隊(duì)列的元素必須都集聚后才能統(tǒng)一進(jìn)行安排佛掖,否則一直等待涌庭。
這往往出現(xiàn)在那些大規(guī)模分布式并行計(jì)算的應(yīng)用場(chǎng)景了:最終的合并計(jì)算需要基于很多并行計(jì)算的子結(jié)果來進(jìn)行。這些隊(duì)列其實(shí)是FIFO隊(duì)列的基礎(chǔ)上進(jìn)行了
增強(qiáng)坐榆,大致的設(shè)計(jì)思想如下:開始時(shí),/queue_barrier
節(jié)點(diǎn)是一個(gè)已經(jīng)存在的默認(rèn)節(jié)點(diǎn)席镀,并且將其節(jié)點(diǎn)的數(shù)據(jù)內(nèi)容賦值為一個(gè)數(shù)字n來代表Barrier值,
例如n=10表示只有當(dāng)/queue_barrier
節(jié)點(diǎn)下的子節(jié)點(diǎn)個(gè)數(shù)達(dá)到10后愉昆,才會(huì)打開Barrier。之后跛溉,所有的客戶端都會(huì)到/queue_barrier
節(jié)點(diǎn)下創(chuàng)建一個(gè)
臨時(shí)節(jié)點(diǎn),例如/queue_barrier/192.168.0.1
芳室,如下圖:
![](http://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/learn/paxos2zookeeper/Paxos2zookeeper-6-1-22.png)
創(chuàng)建完節(jié)點(diǎn)之后,根據(jù)如下5個(gè)步驟來確定執(zhí)行順序嚎尤。
- 通過調(diào)用getDate()接口獲取
/queue_barrier
節(jié)點(diǎn)的數(shù)據(jù)內(nèi)容:10。 - 通過調(diào)用getChildren()接口獲取
/queue_barrier
節(jié)點(diǎn)下的所有子節(jié)點(diǎn)芽死,即獲取隊(duì)列中所有元素,同時(shí)注冊(cè)對(duì)子節(jié)點(diǎn)列表變更的Watcher監(jiān)聽关贵。 - 統(tǒng)計(jì)子節(jié)點(diǎn)的個(gè)數(shù)卖毁。
- 如果子節(jié)點(diǎn)個(gè)數(shù)還不足10個(gè)揖曾,那么就需要進(jìn)入等待亥啦。
- 接收到Watcher通知后,重復(fù)步驟2翔脱。
博主理解為,如果在很少的時(shí)間內(nèi)届吁,同時(shí)超過了10個(gè)以上的業(yè)務(wù)機(jī)創(chuàng)建了臨時(shí)節(jié)點(diǎn)隶糕,那么業(yè)務(wù)處理的速度并不是恒定的站玄,因?yàn)橛锌赡苓@個(gè)業(yè)務(wù)被11個(gè)機(jī)器處理,
下一個(gè)被12個(gè)業(yè)務(wù)機(jī)處理株旷?