Apache Zookeeper是由Apache Hadoop的子項(xiàng)目發(fā)展而來,于2010年11月正式成為Apache頂級(jí)項(xiàng)目。Zookeeper為分布式應(yīng)用提供高效且可靠的分布式協(xié)調(diào)服務(wù),提供了統(tǒng)一命名服務(wù)、配置管理、分布式鎖等分布式的基礎(chǔ)服務(wù)。Zookeeper并沒有直接采用Paxos算法,而是采用了一種被稱為ZAB(Zookeeper Atomic Broadcast)的一致性協(xié)議。
初識(shí)Zookeeper
Zookeeper是一個(gè)開源的分布式協(xié)調(diào)服務(wù),由Yahoo創(chuàng)建,是Google Chubby的開源實(shí)現(xiàn)。Zookeeper將那些復(fù)雜且容易出錯(cuò)的分布式一致性服務(wù)封裝起來,構(gòu)成一個(gè)高效可靠的原語集,并以一系列簡(jiǎn)單易用的接口提供給用戶使用。
分布式應(yīng)用程序可以基于Zookeeper實(shí)現(xiàn)例如數(shù)據(jù)發(fā)布/訂閱、負(fù)載均衡、命名服務(wù)、協(xié)調(diào)通知、集群管理、Master選舉、分布式鎖、分布式隊(duì)列等功能。Zookeeper可以保證如下分布式一致性特性。
1、順序一致性:從同一個(gè)客戶端發(fā)起的事務(wù)請(qǐng)求,最終將會(huì)嚴(yán)格地按照其發(fā)起順序被應(yīng)用到Zookeeper中;
2、原子性:所有事務(wù)的請(qǐng)求結(jié)果在整個(gè)集群中所有機(jī)器上的應(yīng)用情況是一致的,也就是說,要么在整個(gè)集群中所有機(jī)器上都成功應(yīng)用了某一個(gè)事務(wù),要么都沒有應(yīng)用,沒有中間狀態(tài);
3、單一視圖:無論客戶端連接的是哪個(gè)Zookeeper服務(wù)器,其看到的服務(wù)端數(shù)據(jù)模型都是一致的。
4、實(shí)時(shí)性:Zookeeper僅僅保證在一定的時(shí)間內(nèi),客戶端最終一定能夠從服務(wù)端上讀到最終的數(shù)據(jù)狀態(tài)。
Zookeeper的設(shè)計(jì)目標(biāo)
目標(biāo)一:簡(jiǎn)單的數(shù)據(jù)模型
Zookeeper使得分布式程序能通過一個(gè)共享式的、樹形結(jié)構(gòu)的名字空間來進(jìn)行相互協(xié)調(diào)。
樹形結(jié)構(gòu)的名字空間是指Zookeeper服務(wù)器內(nèi)存中的一個(gè)數(shù)據(jù)模型,由一系列被稱為ZNode的數(shù)據(jù)節(jié)點(diǎn)組成,類似一個(gè)文件系統(tǒng)。
目標(biāo)二:可以構(gòu)建集群
組成Zookeeper集群的每臺(tái)機(jī)器都會(huì)在內(nèi)存中維護(hù)當(dāng)前服務(wù)器狀態(tài),并且每臺(tái)機(jī)器都保持通訊。只要集群中超過一半機(jī)器能夠正常工作,整個(gè)集群就能對(duì)外正常服務(wù)。
目標(biāo)三:順序訪問
對(duì)于來自客戶端的每個(gè)更新請(qǐng)求,Zookeeper都會(huì)分配一個(gè)全局唯一遞增編號(hào),這個(gè)編號(hào)反映了所有事物操作的先后順序,應(yīng)用程序可以使用Zookeeper的這個(gè)特性來實(shí)現(xiàn)更加高層的同步原語。
目標(biāo)四:高性能
Zookeeper將全量數(shù)據(jù)存儲(chǔ)在內(nèi)存中直接對(duì)外服務(wù)(除事務(wù)請(qǐng)求),尤其適合于讀操作為主的應(yīng)用場(chǎng)景。
Zookeeper基本概念
集群角色
最典型的集群角色是Master/Slave模式,Master處理所有寫操作,Slave提供讀服務(wù)。
在Zookeeper中,有Leader、Follower、Observer三種角色。集群中所有機(jī)器通過一個(gè)Leader選舉來決定一臺(tái)機(jī)器作為L(zhǎng)eader,Leader為客戶端提供讀和寫服務(wù)。Follower和Observer都提供讀服務(wù),區(qū)別在于Observer機(jī)器不參與選舉,也不參與寫操作的“過半寫成功”策略,因此Observe可以在不影響寫性能的情況下提升集群的讀性能。
會(huì)話
客戶端與Zookeeper是TCP長(zhǎng)連接,默認(rèn)對(duì)外端口是2181,通過這個(gè)連接,客戶端保持和服務(wù)器的心跳以維護(hù)連接,也能向Zookeeper發(fā)送請(qǐng)求并響應(yīng),同時(shí)還可以接收到注冊(cè)通知。
數(shù)據(jù)節(jié)點(diǎn)(ZNode)
Zookeeper所有數(shù)據(jù)都在內(nèi)存中,模型類似一顆文件樹,ZNode Tree,每個(gè)ZNode節(jié)點(diǎn)都會(huì)保存自己的數(shù)據(jù)內(nèi)容和一系列屬性。
ZNode分為持久節(jié)點(diǎn)和臨時(shí)節(jié)點(diǎn),后者和客戶端會(huì)話綁定。
版本
每個(gè)ZNode,Zookeeper都會(huì)維護(hù)一個(gè)Stat數(shù)據(jù)結(jié)構(gòu)記錄這個(gè)ZNode的三個(gè)數(shù)據(jù)版本:當(dāng)前ZNode版本version、當(dāng)前ZNode子節(jié)點(diǎn)版本cversion、和當(dāng)前Node的ACL版本aversion。
Watcher
事件監(jiān)聽是Zookeeper的重要特性,他允許客戶端在指定節(jié)點(diǎn)注冊(cè)Watcher,并且在事件被觸發(fā)后通知客戶端。
ACL
Access Control Lists,定義了5中權(quán)限:
Create、Read、Write、Delete、Admin
ZAB協(xié)議
在ZooKeeper中所有的事務(wù)請(qǐng)求都由一個(gè)主服務(wù)器也就是Leader來處理,其他服務(wù)器為Follower,Leader將客戶端的事務(wù)請(qǐng)求轉(zhuǎn)換為事務(wù)Proposal,并且將Proposal分發(fā)給集群中其他所有的Follower,然后Leader等待Follwer反饋,當(dāng)有過半數(shù)(>=N/2+1)的Follower反饋信息后,Leader將再次向集群內(nèi)Follower廣播Commit信息,Commit為將之前的Proposal提交。
ZAB協(xié)議中存在著三種狀態(tài),每個(gè)節(jié)點(diǎn)都屬于以下三種中的一種:
1.Looking:系統(tǒng)剛啟動(dòng)時(shí)或者Leader崩潰后正處于選舉狀態(tài)
2.Following:Follower節(jié)點(diǎn)所處的狀態(tài),F(xiàn)ollower與Leader處于數(shù)據(jù)同步階段;
3.Leading:Leader所處狀態(tài),當(dāng)前集群中有一個(gè)Leader為主進(jìn)程;
ZooKeeper啟動(dòng)時(shí)所有節(jié)點(diǎn)初始狀態(tài)為L(zhǎng)ooking,這時(shí)集群會(huì)嘗試選舉出一個(gè)Leader節(jié)點(diǎn),選舉出的Leader節(jié)點(diǎn)切換為L(zhǎng)eading狀態(tài);當(dāng)節(jié)點(diǎn)發(fā)現(xiàn)集群中已經(jīng)選舉出Leader則該節(jié)點(diǎn)會(huì)切換到Following狀態(tài),然后和Leader節(jié)點(diǎn)保持同步;當(dāng)Follower節(jié)點(diǎn)與Leader失去聯(lián)系時(shí)Follower節(jié)點(diǎn)則會(huì)切換到Looking狀態(tài),開始新一輪選舉;在ZooKeeper的整個(gè)生命周期中每個(gè)節(jié)點(diǎn)都會(huì)在Looking、Following、Leading狀態(tài)間不斷轉(zhuǎn)換;

選舉出Leader節(jié)點(diǎn)后ZAB進(jìn)入原子廣播階段,這時(shí)Leader為和自己同步的每個(gè)節(jié)點(diǎn)Follower創(chuàng)建一個(gè)操作序列,一個(gè)時(shí)期一個(gè)Follower只能和一個(gè)Leader保持同步,Leader節(jié)點(diǎn)與Follower節(jié)點(diǎn)使用心跳檢測(cè)來感知對(duì)方的存在;當(dāng)Leader節(jié)點(diǎn)在超時(shí)時(shí)間內(nèi)收到來自Follower的心跳檢測(cè)那Follower節(jié)點(diǎn)會(huì)一直與該節(jié)點(diǎn)保持連接;若超時(shí)時(shí)間內(nèi)Leader沒有接收到來自過半Follower節(jié)點(diǎn)的心跳檢測(cè)或TCP連接斷開,那Leader會(huì)結(jié)束當(dāng)前周期的領(lǐng)導(dǎo),切換到Looking狀態(tài),所有Follower節(jié)點(diǎn)也會(huì)放棄該Leader節(jié)點(diǎn)切換到Looking狀態(tài),然后開始新一輪選舉。
ZAB協(xié)議定義了選舉(election)、發(fā)現(xiàn)(discovery)、同步(sync)、廣播(Broadcast)四個(gè)階段;ZAB選舉(election)時(shí)當(dāng)Follower存在ZXID(事務(wù)ID)時(shí)判斷所有Follower節(jié)點(diǎn)的事務(wù)日志,只有l(wèi)astZXID的節(jié)點(diǎn)才有資格成為L(zhǎng)eader,這種情況下選舉出來的Leader總有最新的事務(wù)日志,基于這個(gè)原因所以ZooKeeper實(shí)現(xiàn)的時(shí)候把發(fā)現(xiàn)(discovery)與同步(sync)合并為恢復(fù)(recovery)階段;
1.Election:在Looking狀態(tài)中選舉出Leader節(jié)點(diǎn),Leader的lastZXID總是最新的;
2.Discovery:Follower節(jié)點(diǎn)向準(zhǔn)Leader推送FOllOWERINFO,該信息中包含了上一周期的epoch,接受準(zhǔn)Leader的NEWLEADER指令,檢查newEpoch有效性,準(zhǔn)Leader要確保Follower的epoch與ZXID小于或等于自身的;
3.sync:將Follower與Leader的數(shù)據(jù)進(jìn)行同步,由Leader發(fā)起同步指令,最總保持集群數(shù)據(jù)的一致性;
4.Broadcast:Leader廣播Proposal與Commit,F(xiàn)ollower接受Proposal與Commit;
5.Recovery:在Election階段選舉出Leader后本階段主要工作就是進(jìn)行數(shù)據(jù)的同步,使Leader具有highestZXID,集群保持?jǐn)?shù)據(jù)的一致性;
選舉(Election)
election階段必須確保選出的Leader具有highestZXID,否則在Recovery階段沒法保證數(shù)據(jù)的一致性,Recovery階段Leader要求Follower向自己同步數(shù)據(jù)沒有Follower要求Leader保持?jǐn)?shù)據(jù)同步,所有選舉出來的Leader要具有最新的ZXID;
在選舉的過程中會(huì)對(duì)每個(gè)Follower節(jié)點(diǎn)的ZXID進(jìn)行對(duì)比只有highestZXID的Follower才可能當(dāng)選Leader;
選舉流程:
1. 每個(gè)Follower都向其他節(jié)點(diǎn)發(fā)送選自身為L(zhǎng)eader的Vote投票請(qǐng)求,等待回復(fù);
2. Follower接受到的Vote如果比自身的大(ZXID更新)時(shí)則投票,并更新自身的Vote,否則拒絕投票;
3. 每個(gè)Follower中維護(hù)著一個(gè)投票記錄表,當(dāng)某個(gè)節(jié)點(diǎn)收到過半的投票時(shí),結(jié)束投票并把該Follower選為L(zhǎng)eader,投票結(jié)束;
ZAB協(xié)議中使用ZXID作為事務(wù)編號(hào),ZXID為64位數(shù)字,低32位為一個(gè)遞增的計(jì)數(shù)器,每一個(gè)客戶端的一個(gè)事務(wù)請(qǐng)求時(shí)Leader產(chǎn)生新的事務(wù)后該計(jì)數(shù)器都會(huì)加1,高32位為L(zhǎng)eader周期epoch編號(hào),當(dāng)新選舉出一個(gè)Leader節(jié)點(diǎn)時(shí)Leader會(huì)取出本地日志中最大事務(wù)Proposal的ZXID解析出對(duì)應(yīng)的epoch把該值加1作為新的epoch,將低32位從0開始生成新的ZXID;ZAB使用epoch來區(qū)分不同的Leader周期;
恢復(fù)(Recovery)
在election階段選舉出來的Leader已經(jīng)具有最新的ZXID,所有本階段的主要工作是根據(jù)Leader的事務(wù)日志對(duì)Follower節(jié)點(diǎn)數(shù)據(jù)進(jìn)行更新;
Leader:Leader生成新的ZXID與epoch,接收Follower發(fā)送過來的FOllOWERINFO(含有當(dāng)前節(jié)點(diǎn)的LastZXID)然后往Follower發(fā)送NEWLEADER;Leader根據(jù)Follower發(fā)送過來的LastZXID根據(jù)數(shù)據(jù)更新策略向Follower發(fā)送更新指令;
同步策略:
1.SNAP:如果Follower數(shù)據(jù)太老,Leader將發(fā)送快照SNAP指令給Follower同步數(shù)據(jù);
2.DIFF:Leader發(fā)送從Follolwer.lastZXID到Leader.lastZXID議案的DIFF指令給Follower同步數(shù)據(jù);
3.TRUNC:當(dāng)Follower.lastZXID比Leader.lastZXID大時(shí),Leader發(fā)送從Leader.lastZXID到Follower.lastZXID的TRUNC指令讓Follower丟棄該段數(shù)據(jù);
Follower:往Leader發(fā)送FOLLOERINFO指令,Leader拒絕就轉(zhuǎn)到Election階段;接收Leader的NEWLEADER指令,如果該指令中epoch比當(dāng)前Follower的epoch小那么Follower轉(zhuǎn)到Election階段;Follower還有主要工作是接收SNAP/DIFF/TRUNC指令同步數(shù)據(jù)與ZXID,同步成功后回復(fù)ACKNETLEADER,然后進(jìn)入下一階段;Follower將所有事務(wù)都同步完成后Leader會(huì)把該節(jié)點(diǎn)添加到可用Follower列表中;
SNAP與DIFF用于保證集群中Follower節(jié)點(diǎn)已經(jīng)Committed的數(shù)據(jù)的一致性,TRUNC用于拋棄已經(jīng)被處理但是沒有Committed的數(shù)據(jù);
廣播(Broadcast)
客戶端提交事務(wù)請(qǐng)求時(shí)Leader節(jié)點(diǎn)為每一個(gè)請(qǐng)求生成一個(gè)事務(wù)Proposal,將其發(fā)送給集群中所有的Follower節(jié)點(diǎn),收到過半Follower的反饋后開始對(duì)事務(wù)進(jìn)行提交,ZAB協(xié)議使用了原子廣播協(xié)議;在ZAB協(xié)議中只需要得到過半的Follower節(jié)點(diǎn)反饋Ack就可以對(duì)事務(wù)進(jìn)行提交,這也導(dǎo)致了Leader幾點(diǎn)崩潰后可能會(huì)出現(xiàn)數(shù)據(jù)不一致的情況,ZAB使用了崩潰恢復(fù)來處理數(shù)字不一致問題;消息廣播使用了TCP協(xié)議進(jìn)行通訊所有保證了接受和發(fā)送事務(wù)的順序性。廣播消息時(shí)Leader節(jié)點(diǎn)為每個(gè)事務(wù)Proposal分配一個(gè)全局遞增的ZXID(事務(wù)ID),每個(gè)事務(wù)Proposal都按照ZXID順序來處理;
Leader節(jié)點(diǎn)為每一個(gè)Follower節(jié)點(diǎn)分配一個(gè)隊(duì)列按事務(wù)ZXID順序放入到隊(duì)列中,且根據(jù)隊(duì)列的規(guī)則FIFO來進(jìn)行事務(wù)的發(fā)送。Follower節(jié)點(diǎn)收到事務(wù)Proposal后會(huì)將該事務(wù)以事務(wù)日志方式寫入到本地磁盤中,成功后反饋Ack消息給Leader節(jié)點(diǎn),Leader在接收到過半Follower節(jié)點(diǎn)的Ack反饋后就會(huì)進(jìn)行事務(wù)的提交,以此同時(shí)向所有的Follower節(jié)點(diǎn)廣播Commit消息,F(xiàn)ollower節(jié)點(diǎn)收到Commit后開始對(duì)事務(wù)進(jìn)行提交。
總的來說,ZAB主要是用來構(gòu)建一個(gè)高可用的分布式數(shù)據(jù)主備系統(tǒng),而Paxos則是構(gòu)建一個(gè)分布式的一致性狀態(tài)機(jī)系統(tǒng)。