上來(lái)就送干貨? 本書(shū)的練習(xí)以及代碼可以再O’Reilly官網(wǎng)網(wǎng)站本書(shū)頁(yè)面下載恩商。
相關(guān)鏈接
1、區(qū)分,單機(jī)多線程和分布式多線程的區(qū)別
在典型的不共享環(huán)境下不同的計(jì)算機(jī)之間不共享除網(wǎng)絡(luò)之外的其他任何信息,言外之意豪诲,就是它們之間能夠溝通的方式只有網(wǎng)絡(luò)榆芦。
2、zookeeper在分布式環(huán)境下的作用:
利用消息傳遞算法實(shí)現(xiàn)同步原語(yǔ)耕蝉,zookeeper提供某種有序共享存儲(chǔ)的組件。
Apache kafka ?利用zookeeper檢測(cè)崩潰夜只,實(shí)現(xiàn)主題的發(fā)現(xiàn)垒在,并發(fā)癡主題的生產(chǎn)和消費(fèi)
Apache Solr ?是一起企業(yè)級(jí)的搜索平臺(tái)。使用ZooKeeper來(lái)存儲(chǔ)集群的元數(shù)據(jù)扔亥,并協(xié)作更新這些元數(shù)據(jù)场躯。
Yahoo!Fetching Service 是爬蟲(chóng)實(shí)現(xiàn)的一部分旅挤,通過(guò)緩存內(nèi)容的方法高效地獲取網(wǎng)頁(yè)信息踢关,同時(shí)確保滿(mǎn)足網(wǎng)頁(yè)服務(wù)器的管理規(guī)則。該服務(wù)器采用zookeeper實(shí)現(xiàn)主節(jié)點(diǎn)的選舉粘茄、奔潰檢測(cè)和元數(shù)據(jù)的存儲(chǔ)签舞。
zookeeper的客戶(hù)端API的強(qiáng)大:
1、保障強(qiáng)一致性柒瓣、有序性和持久性儒搭。
2、實(shí)現(xiàn)通過(guò)的同步原語(yǔ)能力
3芙贫、在實(shí)際的分布式系統(tǒng)中搂鲫,并發(fā)往往導(dǎo)致不正確的行為。ZooKeeper提供了一種簡(jiǎn)單的并發(fā)處理機(jī)制
對(duì)于一致性和持久性的不同需求磺平,最佳時(shí)間還是應(yīng)該講應(yīng)用數(shù)據(jù)和協(xié)同數(shù)據(jù)獨(dú)立開(kāi)魂仍。
1.1.2 ZooKeeper不適用的場(chǎng)景,ZooKeeper不適合用作海量數(shù)據(jù)存儲(chǔ)拣挪,取而代之的可以采用數(shù)據(jù)庫(kù)或者分布式文件系統(tǒng)等擦酌,
分布式系統(tǒng)中的進(jìn)程通訊有兩種選擇:直接通過(guò)網(wǎng)絡(luò)進(jìn)行信息交換,或讀取某些共享的存儲(chǔ)菠劝。ZooKeeper使用的共享存儲(chǔ)模型來(lái)使用應(yīng)用間協(xié)作和同步原語(yǔ)赊舶。對(duì)于共享存儲(chǔ)本身,有需要在進(jìn)程和存儲(chǔ)間進(jìn)行網(wǎng)絡(luò)通訊。網(wǎng)絡(luò)是分布式系統(tǒng)中并行設(shè)計(jì)的基礎(chǔ)锯岖。
備份主節(jié)點(diǎn)卻認(rèn)為主節(jié)點(diǎn)已經(jīng)奔潰,例如節(jié)點(diǎn)負(fù)載很高甫何,導(dǎo)致消息延遲出吹,備份主節(jié)點(diǎn)將接管成功主節(jié)點(diǎn)的角色,執(zhí)行所有必要的程序辙喂,如果一些從節(jié)點(diǎn)無(wú)法與主要主節(jié)點(diǎn)的通信捶牢,如由于網(wǎng)絡(luò)分區(qū)(network partition)錯(cuò)誤導(dǎo)致。針對(duì)這個(gè)場(chǎng)景中導(dǎo)致的問(wèn)題巍耗,我們一般稱(chēng)之為腦裂(split-brain):系統(tǒng)中兩個(gè)獲得多個(gè)部分開(kāi)始獨(dú)立工作秋麸,導(dǎo)致整體行為不一致性。
1.2.3 通信故障
如果一個(gè)從節(jié)點(diǎn)與主節(jié)點(diǎn)的網(wǎng)絡(luò)連接斷開(kāi)炬太,比如網(wǎng)絡(luò)分區(qū)(network partition)導(dǎo)致灸蟆,重新分配一個(gè)任務(wù),可能會(huì)導(dǎo)致兩個(gè)從節(jié)點(diǎn)執(zhí)行相同的任務(wù)亲族。
元數(shù)據(jù):主節(jié)點(diǎn)和從節(jié)點(diǎn)必須具有通過(guò)某種可靠的方式來(lái)保存分配狀態(tài)和執(zhí)行狀態(tài)的能力
1.3分布式協(xié)作的難點(diǎn)
當(dāng)開(kāi)發(fā)分布式應(yīng)用時(shí)炒考,其復(fù)雜性會(huì)立即凸顯出來(lái),例如霎迫,當(dāng)我們的應(yīng)用啟動(dòng)后斋枢,所有不同的進(jìn)程通過(guò)某種方式,需要知道應(yīng)用的配置信息知给,一段時(shí)間之后瓤帚,配置信息也許發(fā)生了很大的變化,我們可以停止所有的進(jìn)程涩赢,重新分發(fā)配置信息的文件戈次,然后重新啟動(dòng),但是重新匹配就會(huì)延長(zhǎng)應(yīng)用的停機(jī)時(shí)間筒扒。
FLP(Fischer Lynch Patternson)這個(gè)結(jié)論證明了在異步通信的分布式系統(tǒng)中朝扼,進(jìn)程奔潰,所有的進(jìn)程可能無(wú)法在這個(gè)比特位的配置上達(dá)成一致霎肯。類(lèi)似定律稱(chēng)為CAP ?表示一致性(Consistency)擎颖,可用性(Avaliability)和分區(qū)容錯(cuò)性(Partition-tolerance),該定力指出观游,當(dāng)設(shè)計(jì)一個(gè)分布式系統(tǒng)時(shí)搂捧,我們希望這種屬性全部滿(mǎn)足,但沒(méi)有系統(tǒng)可以同時(shí)滿(mǎn)足這三種屬性懂缕。因此ZooKeeper的設(shè)計(jì)盡可能滿(mǎn)足一致性和可用性允跑,當(dāng)然,發(fā)生網(wǎng)絡(luò)分區(qū)時(shí)也提高了只讀能力。
我們無(wú)法擁有一個(gè)理想的故障容錯(cuò)聋丝、分布式的索烹、真是的環(huán)境存在的系統(tǒng)來(lái)處理所發(fā)生的所有的問(wèn)題,
適當(dāng)放款目標(biāo):假設(shè)時(shí)鐘在某種范圍內(nèi)是同步的弱睦,大媽也可以犧牲一些網(wǎng)絡(luò)分區(qū)容錯(cuò)的能力百姓,并認(rèn)為其一直是一致的。
1.4 ZooKeeper的成功和注意事項(xiàng)
Paxos算法和虛擬同步技術(shù)Virtual Synchrony况木,通過(guò)這些技術(shù)可以無(wú)縫的處理所發(fā)生的某些變化或情況垒拢,并提供一個(gè)開(kāi)發(fā)者一框架。
2.1 zookeeper基礎(chǔ)
提供元語(yǔ)列表火惊,暴露出每個(gè)原語(yǔ)的實(shí)例化調(diào)用方法求类,并直接控制這些實(shí)例。
比如:分布式鎖機(jī)制組成了一個(gè)重要的原語(yǔ)屹耐,同時(shí)暴露創(chuàng)建create 獲取acquire 和釋放release三個(gè)調(diào)用方法
這種設(shè)計(jì)存在一個(gè)重大的缺陷:首先尸疆,我們要么預(yù)先提出一份詳盡的原語(yǔ)的列表,要么提供API的擴(kuò)展惶岭,以便引入新的原語(yǔ)仓技;其次以這種方式實(shí)現(xiàn)元語(yǔ)的服務(wù)是的應(yīng)用上市了靈活性。
因此在zookeeper中俗他,我們另辟蹊徑脖捻。zookeeper并不直接暴露原語(yǔ),取而代之兆衅,它暴露了由一小部分調(diào)用方法組成的類(lèi)似文件系統(tǒng)的API地沮,以便允許應(yīng)用實(shí)現(xiàn)自己的原語(yǔ)。我們通常使用菜譜(recipes)來(lái)表示這些原語(yǔ)羡亩。菜譜包括zookeeper操作和維護(hù)的一個(gè)小型的數(shù)據(jù)節(jié)點(diǎn)摩疑,這些數(shù)據(jù)節(jié)點(diǎn)被稱(chēng)為znode,采用類(lèi)似于文件系統(tǒng)的層級(jí)樹(shù)狀結(jié)構(gòu)進(jìn)行管理畏铆。
2.1.1 API概述
znode 節(jié)點(diǎn)可能還有數(shù)據(jù)雷袋,也可能沒(méi)有,如果一個(gè)znode節(jié)點(diǎn)包含任何數(shù)據(jù)辞居,那么數(shù)據(jù)存儲(chǔ)為字節(jié)數(shù)組byte array楷怒。ZooKeeper并不直接提供解析支持。我們可以使用Protocol buffers 瓦灶, Thrift鸠删、Avro或者M(jìn)essagePack等序列化(Serialization)包來(lái)方便的處理保存于znode節(jié)點(diǎn)的數(shù)據(jù)格式。不過(guò)有時(shí)候UTF-8和ASC2編碼的字符串就夠用了贼陶。
zookeeper的API暴露了以下的方法:
carete ?/path data
創(chuàng)建一個(gè)名為 /path 的node 節(jié)點(diǎn)刃泡,包含數(shù)據(jù)data巧娱。
delete /path
刪除名為 /path的znode
exists /path
檢查是否存在名為 /path的節(jié)點(diǎn)
setData /path data
設(shè)置名為/path 的znode的數(shù)據(jù)為data
getData /path
返回名為/path節(jié)點(diǎn)的數(shù)據(jù)信息
getChildren /path
返回所有 /path節(jié)點(diǎn)的所有子節(jié)點(diǎn)的列表。
zookeeper客戶(hù)端連接到zookeeper服務(wù)烘贴,通過(guò)API調(diào)用來(lái)建立會(huì)話(huà)session禁添。
2.1.2 znode的不同類(lèi)型
持久檢點(diǎn)和臨時(shí)節(jié)點(diǎn)
znode節(jié)點(diǎn)可以是持久(persistent)節(jié)點(diǎn),還可以是臨時(shí)(ephemeral)節(jié)點(diǎn)桨踪。持久的znode老翘,如/path,只能通過(guò)調(diào)用delete來(lái)進(jìn)行刪除馒闷。臨時(shí)的znode與之相反酪捡,當(dāng)穿件該節(jié)點(diǎn)的客戶(hù)端崩潰的時(shí)或者關(guān)閉與zookeeper的鏈接時(shí)叁征,這個(gè)節(jié)點(diǎn)就會(huì)被刪除纳账。
持久znode是一種非常有用的znode,可以通過(guò)持久類(lèi)型的znode為應(yīng)用保存一些數(shù)據(jù)捺疼。
臨時(shí)znode疏虫,在一下兩種情況下會(huì)被刪除;
1啤呼、當(dāng)創(chuàng)建該znode的客戶(hù)端的會(huì)話(huà)因超時(shí)或者注定關(guān)閉而終止
2卧秘、當(dāng)某個(gè)客戶(hù)端主動(dòng)刪除該節(jié)點(diǎn)時(shí)候。
版本機(jī)制
假設(shè)客戶(hù)端C1對(duì)znode /config寫(xiě)入一些配置信息官扣,如果另一個(gè)客戶(hù)端C2同時(shí)更新了這個(gè)znode翅敌,此時(shí)c1的版本號(hào)已經(jīng)過(guò)期,c1調(diào)用setData一定不會(huì)成功惕蹄。使用版本機(jī)制有效避免了以上情況蚯涮。在這個(gè)例子中,C1在寫(xiě)入數(shù)據(jù)使用的版本無(wú)法匹配卖陵,是的操作失敗遭顶。
2.2zookeeper架構(gòu)
zookeeper服務(wù)器端運(yùn)行于兩種模式下:獨(dú)立模式standalone,沖裁模式quorum泪蔫。
在仲裁模式下棒旗,具有一組zookeeper服務(wù),我們稱(chēng)之為zookeeper集合(zookeeper ensemble)撩荣,它們之前可以進(jìn)行狀態(tài)復(fù)制铣揉,并同時(shí)為服務(wù)于客戶(hù)端請(qǐng)求。
1餐曹、在仲裁模式下老速,利用公共管理領(lǐng)域最小有效投票數(shù),在zookeeper中凸主,則是指為了使得zookeeper工作必須有效的運(yùn)行的服務(wù)的最小數(shù)量橘券。這個(gè)數(shù)字也是服務(wù)器告知客戶(hù)端安全數(shù)據(jù)前,需要保存客戶(hù)端數(shù)據(jù)的最小數(shù)量。
2.2.2會(huì)話(huà)
旁舰,對(duì)zookeeper集合執(zhí)行任何請(qǐng)求前锋华,一個(gè)客戶(hù)端必先與服務(wù)建立會(huì)話(huà)。會(huì)話(huà)的概念非常重要箭窜,對(duì)ZooKeeper的運(yùn)行也非常關(guān)鍵毯焕。客戶(hù)端提交給zookeeper的所有操作均關(guān)聯(lián)在一個(gè)會(huì)話(huà)上磺樱。當(dāng)一個(gè)會(huì)話(huà)因某種原因而中止時(shí)纳猫,在這個(gè)會(huì)話(huà)期間創(chuàng)建的臨時(shí)節(jié)點(diǎn)會(huì)消失。
2.3.2 會(huì)話(huà)的狀態(tài)和聲明周期
會(huì)話(huà)的生命周期lifetime是指會(huì)話(huà)從創(chuàng)建到結(jié)束的時(shí)期竹捉,無(wú)論是會(huì)話(huà)的正常關(guān)閉還是因超時(shí)而導(dǎo)致過(guò)期芜辕。
狀態(tài):CONNECTING\CONNECTED\CLOSED\NOT_CONNECTED
開(kāi)始——>NOT_CONNECTED
———>CONNECTING
———>CONNECTED
當(dāng)發(fā)生斷開(kāi)或者無(wú)法收到服務(wù)器超時(shí)時(shí)
————>CONNECTING
當(dāng)服務(wù)器確認(rèn)會(huì)話(huà)有效后,狀態(tài)會(huì)轉(zhuǎn)回CONNECTED狀態(tài)块差。
否則聲明會(huì)話(huà)過(guò)期侵续,然后轉(zhuǎn)到CLOSED狀態(tài)。
———
創(chuàng)建一個(gè)會(huì)時(shí)憨闰,你需要設(shè)置會(huì)話(huà)超時(shí)這個(gè)重要的參數(shù)状蜗,這個(gè)參數(shù)設(shè)置了zookeeper服務(wù)允許會(huì)話(huà)
被聲明為超時(shí)之前存在的時(shí)間。如果經(jīng)過(guò)時(shí)間t之后鹉动,服務(wù)接受不到這個(gè)會(huì)話(huà)的任何消息轧坎,服務(wù)就會(huì)聲明會(huì)話(huà)過(guò)期。而在客戶(hù)端側(cè)泽示,如果經(jīng)過(guò)t/3的時(shí)間未收到任何消息缸血,客戶(hù)端將向服務(wù)器發(fā)送心跳消息。經(jīng)過(guò)2t/3的時(shí)間后边琉,zookeeper客戶(hù)端開(kāi)始尋找其他的服務(wù)器属百,而此時(shí)它還有t/3的時(shí)間去尋找。
尋找可用服務(wù)器列表是通過(guò)給服務(wù)器發(fā)送可用服務(wù)器地址列表的方式實(shí)現(xiàn)变姨。
2.3.3zookeeper與仲裁模式
配置:
tickTime=2000
initLimit=10
synclimit=5
dataDir=./data
clientPort=2181
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445
每一個(gè)server.h項(xiàng)指定了編號(hào)為n的zookeeper服務(wù)器使用的地址和端口號(hào)族扰。每個(gè)server.h項(xiàng)通過(guò)冒號(hào)分隔為三部分,第一部分為服務(wù)器n的Ip地址或主機(jī)名稱(chēng)hostname定欧,第二部分和第三部分為T(mén)CP端口號(hào)渔呵,分別為仲裁通信和群首選舉。
穿件data目錄
mkdir z1
mkdir z1/data
mkdir z2
mkdir z2/data
mkdir z3
mkdir z3/data
當(dāng)啟動(dòng)一個(gè)服務(wù)時(shí)砍鸠,我們需要知道啟動(dòng)的是哪個(gè)服務(wù)器扩氢,一個(gè)服務(wù)器通過(guò)讀取data目錄下的名為myid的文件來(lái)獲得服務(wù)器ID信息,通過(guò)以下命令來(lái)創(chuàng)建這些文件
echo 1> z1/data/myid
echo 2> z2/data/myid
echo 3 > z3/data/myid
在同一臺(tái)機(jī)器上需要?jiǎng)?chuàng)建z1/z1.cfg ? z2/z2.cfg ?z3/z3.cfg
zkServer.sh ./z1.cfg
注意:簡(jiǎn)單的負(fù)載均衡
客戶(hù)端以隨機(jī)順序連接串中的服務(wù)器爷辱。這樣可以用zookeeper來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的負(fù)載均衡录豺。不過(guò)客戶(hù)端無(wú)法指定優(yōu)先選擇的服務(wù)器來(lái)進(jìn)行連接朦肘。例如我們有5個(gè)zookeeper服務(wù)器的集合,
第二部分
使用zookeeper進(jìn)行開(kāi)發(fā)
例子代碼
https://github.com/fpj/zookeeper-book-example
zookeeper java api進(jìn)行開(kāi)發(fā):
順序和ConnectionLossException
zooKeeper會(huì)嚴(yán)格維護(hù)執(zhí)行順序双饥,并提供強(qiáng)有力的有序保障媒抠,然而,在多線程下還是需要小心面對(duì)順序問(wèn)題咏花。在多線程下趴生,當(dāng)回調(diào)函數(shù)中包括重試邏輯的代碼時(shí),一些常見(jiàn)的場(chǎng)景都可能導(dǎo)致錯(cuò)誤發(fā)生昏翰。當(dāng)遇到connectionLossExceptin異常補(bǔ)發(fā)一個(gè)請(qǐng)求時(shí)苍匆,新建立的請(qǐng)求可能排序在其他線程中的請(qǐng)求之后,而實(shí)際上其他線程中的請(qǐng)求應(yīng)該在原來(lái)請(qǐng)求之后棚菊。
3.5任務(wù)隊(duì)列化
第四章 ?處理狀態(tài)變化
4.1 ?單次觸發(fā)器
我們所說(shuō)的事件(event)表示一個(gè)znode節(jié)點(diǎn)執(zhí)行更新操作浸踩。而一個(gè)監(jiān)視點(diǎn)(watch)表示一個(gè)與之關(guān)聯(lián)的znode節(jié)點(diǎn)和時(shí)間類(lèi)型組成的單次觸發(fā)器(例如:znode節(jié)點(diǎn)的數(shù)據(jù)被賦值,或znode節(jié)點(diǎn)被刪除)窍株。當(dāng)一個(gè)監(jiān)視點(diǎn)被一個(gè)事件觸發(fā)時(shí)民轴,就會(huì)產(chǎn)生一個(gè)通知(notification)攻柠。通知是注冊(cè)了監(jiān)視點(diǎn)的應(yīng)用客戶(hù)端收到的事件報(bào)告的消息球订。
當(dāng)應(yīng)用程序注冊(cè)了一個(gè)監(jiān)視點(diǎn)來(lái)接收通知,匹配該監(jiān)視點(diǎn)條件的第一個(gè)事件會(huì)觸發(fā)監(jiān)視點(diǎn)的通知瑰钮。并且最多只觸發(fā)一次冒滩。當(dāng)znode節(jié)點(diǎn)/z被刪除,客戶(hù)端需要知道該變化(例如浪谴,表示備份主節(jié)點(diǎn))开睡,客戶(hù)端在/z節(jié)點(diǎn)執(zhí)行exists操作并設(shè)置監(jiān)視點(diǎn)標(biāo)志位,等待通知苟耻,客戶(hù)端會(huì)以回調(diào)函數(shù)的形式受到通知篇恒。
客戶(hù)端設(shè)置的每個(gè)監(jiān)視點(diǎn)與會(huì)話(huà)關(guān)聯(lián),如果會(huì)話(huà)過(guò)期凶杖,期待中的監(jiān)視點(diǎn)將會(huì)被刪除胁艰。不過(guò)監(jiān)視點(diǎn)可以擴(kuò)月不同的服務(wù)端連接而保持,例如智蝠,當(dāng)一個(gè)zookeeper客戶(hù)端與一個(gè)zookeeper服務(wù)端的連接斷開(kāi)后連接到集合中的另一個(gè)服務(wù)器腾么,客戶(hù)端會(huì)發(fā)送未觸發(fā)的監(jiān)視點(diǎn)列表,在注冊(cè)監(jiān)視點(diǎn)時(shí)杈湾,服務(wù)端將要檢查已監(jiān)視的znode節(jié)點(diǎn)在之前注冊(cè)監(jiān)視點(diǎn)之后是否已經(jīng)變化解虱,如果znode節(jié)點(diǎn)已經(jīng)發(fā)生變化,一個(gè)監(jiān)視點(diǎn)的事件就會(huì)被發(fā)送給客戶(hù)端漆撞,否則在新的服務(wù)端上注冊(cè)監(jiān)視點(diǎn)殴泰。
單次觸發(fā)是否會(huì)丟失事件
答案是肯定的于宙。一個(gè)應(yīng)用在接收到通知后,注冊(cè)另一個(gè)監(jiān)視點(diǎn)時(shí)悍汛,可能會(huì)丟失事件限煞,不過(guò),這個(gè)問(wèn)題需要再深入探討员凝,丟失事件通常并不是問(wèn)題署驻,因?yàn)槿魏卧诮邮芡ㄖc注冊(cè)新監(jiān)視點(diǎn)之間的變化情況,均可以通過(guò)讀取zookeeper的狀態(tài)信息來(lái)獲得健霹。
假設(shè)一個(gè)節(jié)點(diǎn)接收到一個(gè)新任務(wù)分配給它的通知旺上,為了接受新任務(wù),從節(jié)點(diǎn)讀取任務(wù)列表糖埋,如果在通知接收后宣吱,又給這個(gè)從節(jié)點(diǎn)分配了更多的任務(wù),通過(guò)getchildren調(diào)用任務(wù)獲取任務(wù)列表時(shí)會(huì)返回所有的任務(wù)瞳别。同時(shí)調(diào)用getchildren時(shí)也可以設(shè)置新的監(jiān)視點(diǎn)征候,從而保證從節(jié)點(diǎn)不會(huì)丟失任務(wù)。
實(shí)際上祟敛,將多個(gè)事件分?jǐn)偟揭粋€(gè)通知上是具有積極的作用疤坝,比如,應(yīng)用進(jìn)行高頻率的更新操作時(shí)馆铁,這種通知機(jī)制比每個(gè)時(shí)間都發(fā)送通知更加輕量化跑揉。舉例子,如果每個(gè)通知平均補(bǔ)貨兩個(gè)事件埠巨,我們?yōu)槊總€(gè)時(shí)間只產(chǎn)生0.5個(gè)通知历谍,而不是每個(gè)事件1個(gè)通知。
4.2如何設(shè)置監(jiān)視點(diǎn)
Zookeeper的API中的所有讀操作:getData辣垒,getChildren和exits望侈,均可以選擇在讀取的znode節(jié)點(diǎn)上設(shè)置監(jiān)視點(diǎn)。使用監(jiān)視點(diǎn)機(jī)制勋桶,我們需要實(shí)現(xiàn)watcher接口脱衙,實(shí)現(xiàn)其中的process方法:
public void process(WatchedEvent event);
zookeeper會(huì)話(huà)狀態(tài):keeperSate:Disconnected哥遮、SyncConnected岂丘、AuthFailed、ConnectedReadOnly眠饮、SasAuthenticated和Expired奥帘。
事件類(lèi)型(EventType):NodeCreated、NodeDeleted仪召、NodeDataChanged寨蹋、NodeChildrenChanged和None松蒜。
NodeCreated
通過(guò)exists調(diào)用設(shè)置一個(gè)監(jiān)視點(diǎn)。
NodeDeleted
通過(guò)exists或者getData調(diào)用設(shè)置監(jiān)視點(diǎn)已旧。
NodeDataChanged
通過(guò)exists或者getData調(diào)用設(shè)置監(jiān)視點(diǎn)
nodeChildrenChanged
通過(guò)getChildren調(diào)用設(shè)置監(jiān)視點(diǎn)秸苗。
4.3普遍模型
1、進(jìn)行調(diào)用異步
2运褪、實(shí)現(xiàn)回調(diào)對(duì)象惊楼,并傳入異步調(diào)用函數(shù)中
3、如果操作需要設(shè)置監(jiān)視點(diǎn)秸讹,實(shí)現(xiàn)一個(gè)watcher對(duì)象檀咙,并傳入異步調(diào)用函數(shù)中。
4.4主從模式的例子
現(xiàn)在璃诀,我們通過(guò)主從模式的例子來(lái)看看如何處理狀態(tài)的變化弧可。以下為一個(gè)任務(wù)列表,一個(gè)組件需要等待處理的變化情況:
1劣欢、管理權(quán)變化
2棕诵、主節(jié)點(diǎn)等待從節(jié)點(diǎn)列表的變化
3、主節(jié)點(diǎn)等待新任務(wù)進(jìn)行分配
4凿将、從節(jié)點(diǎn)等待分配新任務(wù)
5校套、客戶(hù)端等待任務(wù)的執(zhí)行結(jié)果
4.5另一種調(diào)用方式
我們希望大多數(shù)應(yīng)用采用我們之前所討論的模式,即使是該模式的各種變體也可以丸相。我們專(zhuān)注于異步API搔确,并且建議開(kāi)發(fā)者也使用異步的方式彼棍,異步API可以讓?xiě)?yīng)用程序變得更加有效使用zookeeper資源灭忠、同時(shí)獲得更高的性能。
8座硕、Curator ? ? Zookeeper API的高級(jí)封裝庫(kù)
Curator作為zookeeper的一個(gè)高層次封裝庫(kù)弛作,為開(kāi)發(fā)人員封裝了一組開(kāi)發(fā)庫(kù),Curator的核心目的是為你管理zookeeper的相關(guān)操作
CuratorFramework
8.2 ?劉暢式API
流暢式API可以讓我們編寫(xiě)鏈?zhǔn)秸{(diào)用的代碼华匾,而不用在進(jìn)行請(qǐng)求操作時(shí)采用嚴(yán)格的簽名方案映琳。
實(shí)現(xiàn)異步調(diào)用的回調(diào)處理。假設(shè)在之前的調(diào)用中蜘拉,回調(diào)方式將會(huì)通過(guò)create事件傳遞給注冊(cè)的監(jiān)聽(tīng)器萨西。inBackground調(diào)用可以傳入一個(gè)上下文對(duì)象,銅鼓該參數(shù)可以傳入一個(gè)具體的回調(diào)方法的實(shí)現(xiàn)旭旭。
第9章
ZooKeeper 內(nèi)部原理
服務(wù)器對(duì)客戶(hù)端發(fā)送的請(qǐng)求操作了哪些工作谎脯?
群首和追隨者組成了保障狀態(tài)變化有序的核心實(shí)體,同時(shí)還存在第三類(lèi)服務(wù)器持寄,稱(chēng)為觀察者(observer)源梭。
觀察者不會(huì)參與決策哪些請(qǐng)求可被接受的過(guò)程娱俺,只是觀察決策的結(jié)果,觀察者的設(shè)計(jì)師為了系統(tǒng)的可擴(kuò)展性废麻。
那些會(huì)改變Zookeeper狀態(tài)的客戶(hù)端請(qǐng)求create荠卷、delete和setData)將會(huì)被轉(zhuǎn)發(fā)給群首、群首執(zhí)行相應(yīng)的請(qǐng)求烛愧,并形成狀態(tài)的更新油宜,我們成為事務(wù)(transaction)
事務(wù)的冪等性:可以對(duì)同一個(gè)事務(wù)執(zhí)行多次,得到的結(jié)果都一樣怜姿,前提是我們確保多個(gè)事務(wù)的執(zhí)行順序每次都是一樣的验庙。事務(wù)的冪等性可以讓我們?cè)谶M(jìn)行恢復(fù)處理時(shí)更加簡(jiǎn)單。
當(dāng)群首產(chǎn)生了一個(gè)事務(wù)社牲,就會(huì)為該事務(wù)分配一個(gè)表示符粪薛,我們稱(chēng)之為zookeeper會(huì)話(huà)ID (zxid),通過(guò)zxid對(duì)事務(wù)進(jìn)行標(biāo)識(shí)搏恤,就可以按照群首所指定的順序在各個(gè)服務(wù)器中按序執(zhí)行违寿。
服務(wù)器之間在進(jìn)行新的群首選舉時(shí)也會(huì)交換zxid信息,這樣就可以知道哪個(gè)無(wú)故障服務(wù)器接受了更多的事務(wù)熟空,并可以同步他們之間的狀態(tài)信息藤巢。這樣就知道哪個(gè)無(wú)故障服務(wù)器接受了更多的事務(wù),并可以同步他們之間的狀態(tài)信息息罗。
zxid為一個(gè)long型64位整數(shù)掂咒,分為兩部分:時(shí)間戳(epoch)部分和計(jì)數(shù)器counter兩部分,每部分為32位迈喉,在我們討論zab協(xié)議時(shí)绍刮,我們就發(fā)現(xiàn)時(shí)間錯(cuò)epoch和計(jì)數(shù)器counter的具體作用,我們通過(guò)該協(xié)議來(lái)廣播各個(gè)服務(wù)器的狀態(tài)變更信息挨摸。
9.2群首選舉
設(shè)置群首的目的是為了對(duì)客戶(hù)端發(fā)起的zookeeper狀態(tài)變更請(qǐng)求進(jìn)行排序孩革,包括create、setData得运,delete操作膝蜈。群首將每一個(gè)請(qǐng)求轉(zhuǎn)化為一個(gè)事務(wù),將這些事務(wù)發(fā)送給追隨者熔掺,確保集群按照確定的順序接受并處理這些事務(wù)饱搏。
仲裁(quorum)
仲裁模式要求服務(wù)器之間兩兩相交。
每個(gè)服務(wù)器啟動(dòng)后進(jìn)入LOOKING狀態(tài)置逻,開(kāi)始選舉一個(gè)新的群首或查找已經(jīng)存在的群首推沸,如果群首已經(jīng)存在,其他服務(wù)器就會(huì)通知這個(gè)新啟動(dòng)的服務(wù)器诽偷,告知那個(gè)服務(wù)器是群首坤学,于此同時(shí)疯坤,新的服務(wù)器會(huì)與群首建立連接,以確保自己的狀態(tài)與群首一致深浮。
如果集群中所有的服務(wù)器均處于LOOKING狀態(tài)压怠,這些服務(wù)器之間就會(huì)進(jìn)行通信來(lái)選舉一個(gè)群首,通過(guò)信息交換對(duì)群首選舉達(dá)成共識(shí)的選擇飞苇,本次選舉過(guò)程中勝出的服務(wù)器將進(jìn)入LEADING狀態(tài)
對(duì)于群首選擇的消息菌瘫,我們稱(chēng)之為群首選舉通知消息(leader eletion notifications),或簡(jiǎn)單地稱(chēng)為通知(notifications)布卡。該協(xié)議非常簡(jiǎn)單雨让,當(dāng)一個(gè)服務(wù)器進(jìn)行LOOKING狀態(tài),就會(huì)向集群中每個(gè)服務(wù)器發(fā)送一個(gè)通知消息忿等,該消息中包括服務(wù)器的投標(biāo)vote信息栖忠,投票中包含服務(wù)器標(biāo)識(shí)符(sid)和最近執(zhí)行的事務(wù)的zxid信息。比如贸街,一個(gè)服務(wù)器所發(fā)送的投標(biāo)信息為(1庵寞,5),該服務(wù)器表示的sid為1薛匪,最近執(zhí)行的事務(wù)的zxid為5.
當(dāng)一個(gè)服務(wù)器收到一個(gè)投票信息捐川,該服務(wù)器將會(huì)根據(jù)以下規(guī)則修改自己的投票信息:
1、將收到的Voteid和votezxid作為標(biāo)識(shí)符逸尖,并獲取接收方當(dāng)前的投票中的zxid古沥,用myzxid和mysid表示接收方服務(wù)器自己的值
2、如果votezxid>myzxid或者votezxid = myzxid且 voteid>myid娇跟,保留當(dāng)前的投票信息岩齿。
3、否則逞频,修改自己的投票信息纯衍,將votezxid賦值給myzxid,將voteid賦值給mySid苗胀,簡(jiǎn)而言之,只有最新的服務(wù)器將贏得選舉瓦堵,因?yàn)槠鋼碛凶罱粋€(gè)的zxid基协,如果多個(gè)服務(wù)器擁有最新的zxid值,其中的sid值最大的將贏得選舉菇用。
查找群首
在Zookeeper中對(duì)應(yīng)實(shí)現(xiàn)選舉的java類(lèi)為QuorumPeer澜驮,其中的run方法實(shí)現(xiàn)了服務(wù)器的主要工作循環(huán)。當(dāng)進(jìn)入LOOKING狀態(tài)惋鸥,將會(huì)執(zhí)行l(wèi)ookForLeader方法來(lái)進(jìn)行群首的選舉杂穷,該方法主要執(zhí)行我們剛剛所討論為協(xié)議悍缠。在方法返回前,在該方法中會(huì)將服務(wù)器狀態(tài)設(shè)置為L(zhǎng)EADING或FOLLOWING狀態(tài)耐量,當(dāng)然還可能為OBSERVING狀態(tài)飞蚓,如果服務(wù)器稱(chēng)為群首,就會(huì)創(chuàng)建一個(gè)leader對(duì)象并運(yùn)行這個(gè)對(duì)象廊蜒。如果服務(wù)器為追隨者趴拧,就會(huì)創(chuàng)建一個(gè)Follower對(duì)象并進(jìn)行運(yùn)行。
并不是所有執(zhí)行過(guò)程山叮,服務(wù)器s2做出了錯(cuò)誤判斷著榴,選擇了另一個(gè)服務(wù)器s3不是服務(wù)器s1,雖然s1的zxid值更高屁倔,但在從服務(wù)器s1向服務(wù)器s2傳送消息時(shí)發(fā)生了網(wǎng)絡(luò)故障導(dǎo)致長(zhǎng)時(shí)間延遲脑又,與此同時(shí)腻要,服務(wù)器s2選擇服務(wù)器s3作為群首搬设,最終,服務(wù)器s1和服務(wù)器s3組成了仲裁數(shù)量quorum繁堡,并忽略服務(wù)器s2.
9.3 Zab:ZooKeeper原子廣播協(xié)議(ZooKeeper Atomic Broadcast protocol)