Zookeeper 原理
Zookeeper的基本概念
角色
Zookeeper中的角色主要有以下三類,如下表所示:
系統(tǒng)模型如圖所示:
設計目的
最終一致性:client不論連接到哪個Server泽示,展示給它都是同一個視圖往枷,這是zookeeper最重要的性能更耻。
可靠性:具有簡單自沧、健壯纵柿、良好的性能序矩,如果消息m被到一臺服務器接受鸯绿,那么它將被所有的服務器接受。
實時性:Zookeeper保證客戶端將在一個時間間隔范圍內(nèi)獲得服務器的更新信息簸淀,或者服務器失效的信息瓶蝴。但由于網(wǎng)絡延時等原因,Zookeeper不能保證兩個客戶端能同時得到剛更新的數(shù)據(jù)租幕,如果需要最新數(shù)據(jù)舷手,應該在讀數(shù)據(jù)之前調(diào)用sync()接口。
等待無關(wait-free):慢的或者失效的client不得干預快速的client的請求令蛉,使得每個client都能有效的等待聚霜。
原子性:更新只能成功或者失敗狡恬,沒有中間狀態(tài)。
順序性:包括全局有序和偏序兩種:全局有序是指如果在一臺服務器上消息a在消息b前發(fā)布蝎宇,則在所有Server上消息a都將在消息b前被發(fā)布弟劲;偏序是指如果一個消息b在消息a后被同一個發(fā)送者發(fā)布,a必將排在b前面姥芥。
ZooKeeper的工作原理
Zookeeper的核心是原子廣播兔乞,這個機制保證了各個Server之間的同步。實現(xiàn)這個機制的協(xié)議叫做Zab協(xié)議凉唐。Zab協(xié)議有兩種模式庸追,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰后台囱,Zab就進入了恢復模式淡溯,當領導者被選舉出來,且大多數(shù)Server完成了和leader的狀態(tài)同步以后簿训,恢復模式就結(jié)束了咱娶。狀態(tài)同步保證了leader和Server具有相同的系統(tǒng)狀態(tài)。
為了保證事務的順序一致性强品,zookeeper采用了遞增的事務id號(zxid)來標識事務膘侮。所有的提議(proposal)都在被提出的時候加上了zxid。實現(xiàn)中zxid是一個64位的數(shù)字的榛,它高32位是epoch用來標識leader關系是否改變琼了,每次一個leader被選出來,它都會有一個新的epoch夫晌,標識當前屬于那個leader的統(tǒng)治時期雕薪。低32位用于遞增計數(shù)。
每個Server在工作過程中有三種狀態(tài):
LOOKING:當前Server不知道leader是誰慷丽,正在搜尋
LEADING:當前Server即為選舉出來的leader
FOLLOWING:leader已經(jīng)選舉出來蹦哼,當前Server與之同步
選主流程
當leader崩潰或者leader失去大多數(shù)的follower,這時候zk進入恢復模式要糊,恢復模式需要重新選舉出一個新的leader纲熏,讓所有的Server都恢復到一個正確的狀態(tài)。Zk的選舉算法有兩種:一種是基于basic paxos實現(xiàn)的锄俄,另外一種是基于fast paxos算法實現(xiàn)的局劲。系統(tǒng)默認的選舉算法為fast paxos。先介紹basic paxos流程:
選舉線程由當前Server發(fā)起選舉的線程擔任奶赠,其主要功能是對投票結(jié)果進行統(tǒng)計鱼填,并選出推薦的Server;
選舉線程首先向所有Server發(fā)起一次詢問(包括自己)毅戈;
選舉線程收到回復后苹丸,驗證是否是自己發(fā)起的詢問 (驗證zxid是否一致)愤惰,然后獲取對方的id (myid),并存儲到當前詢問對象列表中赘理,最后獲取對方提議的leader相關信息 (id,zxid)宦言,并將這些信息存儲到當次選舉的投票記錄表中;
收到所有Server回復以后商模,就計算出zxid最大的那個Server奠旺,并將這個Server相關信息設置成下一次要投票的Server;
線程將當前zxid最大的Server設置為當前Server要推薦的Leader施流,如果此時獲勝的Server獲得n/2 + 1的Server票數(shù)响疚,設置當前推薦的leader為獲勝的Server,將根據(jù)獲勝的Server相關信息設置自己的狀態(tài)瞪醋,否則忿晕,繼續(xù)這個過程,直到leader被選舉出來银受。
通過流程分析我們可以得出:要使Leader獲得多數(shù)Server的支持杏糙,則Server總數(shù)必須是奇數(shù)2n+1,且存活的Server的數(shù)目不得少于n+1蚓土。
每個Server啟動后都會重復以上流程。在恢復模式下赖淤,如果是剛從崩潰狀態(tài)恢復的或者剛啟動的server還會從磁盤快照中恢復數(shù)據(jù)和會話信息蜀漆,zk會記錄事務日志并定期進行快照,方便在恢復時進行狀態(tài)恢復咱旱。選主的具體流程圖如下所示:
fast paxos流程是在選舉過程中确丢,某Server首先向所有Server提議自己要成為leader,當其它Server收到提議以后吐限,解決epoch和zxid的沖突鲜侥,并接受對方的提議,然后向?qū)Ψ桨l(fā)送接受提議完成的消息诸典,重復這個流程描函,最后一定能選舉出Leader。其流程圖如下所示:
同步流程
選完leader以后狐粱,zk就進入狀態(tài)同步過程舀寓。
leader等待server連接;
Follower連接leader肌蜻,將最大的zxid發(fā)送給leader互墓;
Leader根據(jù)follower的zxid確定同步點;
完成同步后通知follower 已經(jīng)成為uptodate狀態(tài)蒋搜;
Follower收到uptodate消息后篡撵,又可以重新接受client的請求進行服務了判莉。
流程圖如下所示:
工作流程
Leader工作流程
Leader主要有三個功能:
恢復數(shù)據(jù);
維持與Learner的心跳育谬,接收Learner請求并判斷Learner的請求消息類型券盅;
Learner的消息類型主要有PING消息、REQUEST消息斑司、ACK消息渗饮、REVALIDATE消息,根據(jù)不同的消息類型宿刮,進行不同的處理互站。
PING消息是指Learner的心跳信息;REQUEST消息是Follower發(fā)送的提議信息僵缺,包括寫請求及同步請求胡桃;ACK消息是Follower的對提議的回復,超過半數(shù)的Follower通過磕潮,則commit該提議翠胰;REVALIDATE消息是用來延長SESSION有效時間。
Leader的工作流程簡圖如下所示自脯,在實際實現(xiàn)中之景,流程要比下圖復雜得多,啟動了三個線程來實現(xiàn)功能:
Follower工作流程
Follower主要有四個功能:
向Leader發(fā)送請求(PING消息膏潮、REQUEST消息锻狗、ACK消息、REVALIDATE消息)焕参;
接收Leader消息并進行處理轻纪;
接收Client的請求,如果為寫請求叠纷,發(fā)送給Leader進行投票刻帚;
返回Client結(jié)果。
Follower的消息循環(huán)處理如下幾種來自Leader的消息:
PING消息: 心跳消息涩嚣;
PROPOSAL消息:Leader發(fā)起的提案崇众,要求Follower投票;
COMMIT消息:服務器端最新一次提案的信息缓艳;
UPTODATE消息:表明同步完成校摩;
REVALIDATE消息:根據(jù)Leader的REVALIDATE結(jié)果,關閉待revalidate的session還是允許其接受消息阶淘;
SYNC消息:返回SYNC結(jié)果到客戶端衙吩,這個消息最初由客戶端發(fā)起,用來強制得到最新的更新溪窒。
Follower的工作流程簡圖如下所示坤塞,在實際實現(xiàn)中冯勉,F(xiàn)ollower是通過5個線程來實現(xiàn)功能的。
對于observer的流程不再敘述摹芙,observer流程和Follower的唯一不同的地方就是observer不會參加leader發(fā)起的投票灼狰。
ZooKeeper在大型分布式系統(tǒng)中的應用
前面已經(jīng)介紹了ZooKeeper的典型應用場景。本節(jié)將以常見的大數(shù)據(jù)產(chǎn)品Hadoop和HBase為例來介紹ZooKeeper在其中的應用浮禾,幫助大家更好地理解ZooKeeper的分布式應用場景交胚。
ZooKeeper在Hadoop中的應用
在Hadoop中,ZooKeeper主要用于實現(xiàn)HA (Hive Availability)盈电,包括HDFS的NamaNode和YARN的ResourceManager的HA蝴簇。同時,在YARN中匆帚,ZooKeepr還用來存儲應用的運行狀態(tài)熬词。HDFS的NamaNode和YARN的ResourceManager利用ZooKeepr實現(xiàn)HA的原理是一樣的,所以本節(jié)以YARN為例來介紹吸重。
從上圖可以看出互拾,YARN主要由ResourceManager(RM)、NodeManager(NM)嚎幸、ApplicationMaster(AM)和Container四部分組成颜矿。其中最核心的就是ResourceManager。
ResourceManager負責集群中所有資源的統(tǒng)一管理和分配嫉晶,同時接收來自各個節(jié)點(NodeManager)的資源匯報信息或衡,并把這些信息按照一定的策略分配給各個應用程序(Application Manager),其內(nèi)部維護了各個應用程序的ApplicationMaster信息车遂、NodeManager信息以及資源使用信息等。
為了實現(xiàn)HA斯辰,必須有多個ResourceManager并存(一般就兩個)舶担,并且只有一個ResourceManager處于Active狀態(tài),其他的則處于Standby狀態(tài)彬呻,當Active節(jié)點無法正常工作(如機器宕機或重啟)時衣陶,處于Standby的就會通過競爭選舉產(chǎn)生新的Active節(jié)點。
主備切換
下面我們就來看看YARN是如何實現(xiàn)多個ResourceManager之間的主備切換的闸氮。
1.創(chuàng)建鎖節(jié)點
在ZooKeeper上會有一個/yarn-leader-election/appcluster-yarn
的鎖節(jié)點剪况,所有的ResourceManager在啟動的時候,都會去競爭寫一個Lock子節(jié)點:/yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
蒲跨,該節(jié)點是臨時節(jié)點。ZooKeepr能夠為我們保證最終只有一個ResourceManager能夠創(chuàng)建成功。創(chuàng)建成功的那個ResourceManager就切換為Active狀態(tài)去扣,沒有成功的那些ResourceManager則切換為Standby狀態(tài)。
[zk: localhost:2181(CONNECTED) 16] get /yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
appcluster-yarnrm2
cZxid = 0x1b00133dc0
ctime = Tue Jan 03 15:44:42 CST 2017
mZxid = 0x1f00000540
mtime = Sat Jan 07 00:50:20 CST 2017
pZxid = 0x1b00133dc0
cversion = 0
dataVersion = 28
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 22
numChildren = 0
可以看到此時集群中ResourceManager2為Active堪唐。
2.注冊Watcher監(jiān)聽
所有Standby狀態(tài)的ResourceManager都會向/yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
節(jié)點注冊一個節(jié)點變更的Watcher監(jiān)聽,利用臨時節(jié)點的特性翎蹈,能夠快速感知到Active狀態(tài)的ResourceManager的運行情況淮菠。
3.主備切換
當Active狀態(tài)的ResourceManager出現(xiàn)諸如宕機或重啟的異常情況時,其在ZooKeeper上連接的客戶端會話就會失效荤堪,因此/yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
節(jié)點就會被刪除合陵。此時其余各個Standby狀態(tài)的ResourceManager就都會接收到來自ZooKeeper服務端的Watcher事件通知,然后會重復進行步驟1的操作澄阳。
以上就是利用ZooKeeper來實現(xiàn)ResourceManager的主備切換的過程拥知,實現(xiàn)了ResourceManager的HA。
HDFS中NameNode的HA的實現(xiàn)原理跟YARN中ResourceManager的HA的實現(xiàn)原理相同寇荧。其鎖節(jié)點為/hadoop-ha/mycluster/ActiveBreadCrumb
举庶。
ResourceManager狀態(tài)存儲
在 ResourceManager 中,RMStateStore 能夠存儲一些 RM 的內(nèi)部狀態(tài)信息揩抡,包括 Application 以及它們的 Attempts 信息户侥、Delegation Token 及 Version Information 等。需要注意的是峦嗤,RMStateStore 中的絕大多數(shù)狀態(tài)信息都是不需要持久化存儲的蕊唐,因為很容易從上下文信息中將其重構(gòu)出來,如資源的使用情況烁设。在存儲的設計方案中替梨,提供了三種可能的實現(xiàn),分別如下装黑。
- 基于內(nèi)存實現(xiàn)副瀑,一般是用于日常開發(fā)測試。
- 基于文件系統(tǒng)的實現(xiàn)恋谭,如HDFS糠睡。
- 基于ZooKeeper實現(xiàn)。
由于這些狀態(tài)信息的數(shù)據(jù)量都不是很大疚颊,因此Hadoop官方建議基于ZooKeeper來實現(xiàn)狀態(tài)信息的存儲狈孔。在ZooKeepr上,ResourceManager 的狀態(tài)信息都被存儲在/rmstore這個根節(jié)點下面材义。
[zk: localhost:2181(CONNECTED) 28] ls /rmstore/ZKRMStateRoot
[RMAppRoot, AMRMTokenSecretManagerRoot, EpochNode, RMDTSecretManagerRoot, RMVersionNode]
RMAppRoot 節(jié)點下存儲的是與各個 Application 相關的信息均抽,RMDTSecretManagerRoot 存儲的是與安全相關的 Token 等信息。每個 Active 狀態(tài)的 ResourceManager 在初始化階段都會從 ZooKeeper 上讀取到這些狀態(tài)信息其掂,并根據(jù)這些狀態(tài)信息繼續(xù)進行相應的處理油挥。
小結(jié):
ZooKeepr在Hadoop中的應用主要有:
- HDFS中NameNode的HA和YARN中ResourceManager的HA。
- 存儲RMStateStore狀態(tài)信息
ZooKeeper在HBase中的應用
HBase主要用ZooKeeper來實現(xiàn)HMaster選舉與主備切換、系統(tǒng)容錯喘漏、RootRegion管理护蝶、Region狀態(tài)管理和分布式SplitWAL任務管理等。
HMaster選舉與主備切換
HMaster選舉與主備切換的原理和HDFS中NameNode及YARN中ResourceManager的HA原理相同翩迈。
系統(tǒng)容錯
當HBase啟動時持灰,每個RegionServer都會到ZooKeeper的/hbase/rs
節(jié)點下創(chuàng)建一個信息節(jié)點(下文中,我們稱該節(jié)點為"rs狀態(tài)節(jié)點")负饲,例如/hbase/rs/[Hostname]
堤魁,同時,HMaster會對這個節(jié)點注冊監(jiān)聽返十。當某個 RegionServer 掛掉的時候妥泉,ZooKeeper會因為在一段時間內(nèi)無法接受其心跳(即 Session 失效),而刪除掉該 RegionServer 服務器對應的 rs 狀態(tài)節(jié)點洞坑。與此同時盲链,HMaster 則會接收到 ZooKeeper 的 NodeDelete 通知,從而感知到某個節(jié)點斷開迟杂,并立即開始容錯工作刽沾。
HBase為什么不直接讓HMaster來負責RegionServer的監(jiān)控呢?如果HMaster直接通過心跳機制等來管理RegionServer的狀態(tài)排拷,隨著集群越來越大侧漓,HMaster的管理負擔會越來越重,另外它自身也有掛掉的可能监氢,因此數(shù)據(jù)還需要持久化布蔗。在這種情況下,ZooKeeper就成了理想的選擇浪腐。
RootRegion管理
對應HBase集群來說纵揍,數(shù)據(jù)存儲的位置信息是記錄在元數(shù)據(jù)region,也就是RootRegion上的议街。每次客戶端發(fā)起新的請求骡男,需要知道數(shù)據(jù)的位置,就會去查詢RootRegion傍睹,而RootRegion自身位置則是記錄在ZooKeeper上的(默認情況下,是記錄在ZooKeeper的/hbase/meta-region-server
節(jié)點中)犹菱。當RootRegion發(fā)生變化拾稳,比如Region的手工移動、重新負載均衡或RootRegion所在服務器發(fā)生了故障等是腊脱,就能夠通過ZooKeeper來感知到這一變化并做出一系列相應的容災措施访得,從而保證客戶端總是能夠拿到正確的RootRegion信息。
Region管理
HBase里的Region會經(jīng)常發(fā)生變更,這些變更的原因來自于系統(tǒng)故障悍抑、負載均衡鳄炉、配置修改、Region分裂與合并等搜骡。一旦Region發(fā)生移動拂盯,它就會經(jīng)歷下線(offline)和重新上線(online)的過程。
在下線期間數(shù)據(jù)是不能被訪問的记靡,并且Region的這個狀態(tài)變化必須讓全局知曉谈竿,否則可能會出現(xiàn)事務性的異常。對于大的HBase集群來說摸吠,Region的數(shù)量可能會多達十萬級別空凸,甚至更多,這樣規(guī)模的Region狀態(tài)管理交給ZooKeeper來做也是一個很好的選擇寸痢。
分布式SplitWAL任務管理
當某臺RegionServer服務器掛掉時呀洲,由于總有一部分新寫入的數(shù)據(jù)還沒有持久化到HFile中,因此在遷移該RegionServer的服務時啼止,一個重要的工作就是從WAL中恢復這部分還在內(nèi)存中的數(shù)據(jù)道逗,而這部分工作最關鍵的一步就是SplitWAL,即HMaster需要遍歷該RegionServer服務器的WAL族壳,并按Region切分成小塊移動到新的地址下憔辫,并進行日志的回放(replay)。
由于單個RegionServer的日志量相對龐大(可能有上千個Region仿荆,上GB的日志)贰您,而用戶又往往希望系統(tǒng)能夠快速完成日志的恢復工作。因此一個可行的方案是將這個處理WAL的任務分給多臺RegionServer服務器來共同處理拢操,而這就又需要一個持久化組件來輔助HMaster完成任務的分配锦亦。當前的做法是,HMaster會在ZooKeeper上創(chuàng)建一個SplitWAL節(jié)點(默認情況下令境,是/hbase/SplitWAL
節(jié)點)杠园,將"哪個RegionServer處理哪個Region"這樣的信息以列表的形式存放到該節(jié)點上,然后由各個RegionServer服務器自行到該節(jié)點上去領取任務并在任務執(zhí)行成功或失敗后再更新該節(jié)點的信息舔庶,以通知HMaster繼續(xù)進行后面的步驟抛蚁。ZooKeeper在這里擔負起了分布式集群中相互通知和信息持久化的角色。
小結(jié):
以上就是一些HBase中依賴ZooKeeper完成分布式協(xié)調(diào)功能的典型場景惕橙。但事實上瞧甩,HBase對ZooKeepr的依賴還不止這些,比如HMaster還依賴ZooKeeper來完成Table的enable/disable狀態(tài)記錄弥鹦,以及HBase中幾乎所有的元數(shù)據(jù)存儲都是放在ZooKeeper上的肚逸。
由于ZooKeeper出色的分布式協(xié)調(diào)能力及良好的通知機制,HBase在各版本的演進過程中越來越多地增加了ZooKeeper的應用場景,從趨勢上來看兩者的交集越來越多朦促。HBase中所有對ZooKeeper的操作都封裝在了org.apache.hadoop.hbase.zookeeper這個包中膝晾,感興趣的同學可以自行研究。