淺談分布式服務(wù)協(xié)調(diào)技術(shù) Zookeeper
Google的三篇論文影響了很多很多人,也影響了很多很多系統(tǒng)尼酿。這三篇論文一直是分布式領(lǐng)域傳閱的經(jīng)典。根據(jù)MapReduce,于是我們有了Hadoop笨农;根據(jù)GFS,于是我們有了HDFS帖渠;根據(jù)BigTable谒亦,于是我們有了HBase。而在這三篇論文里都提及Google的一個Lock Service —— Chubby空郊,哦份招,于是我們有了Zookeeper。
隨著大數(shù)據(jù)的火熱狞甚,Hxx們已經(jīng)變得耳熟能詳锁摔,現(xiàn)在作為一個開發(fā)人員如果都不知道這幾個名詞出門都好像不好意思跟人打招呼。但實際上對我們這些非大數(shù)據(jù)開發(fā)人員而言入愧,Zookeeper是比Hxx們可能接觸到更多的一個基礎(chǔ)服務(wù)鄙漏。但是,無奈的是它一直默默的位于二線棺蛛,從來沒有Hxx們那么耀眼怔蚌。那么到底什么是Zookeeper呢?Zookeeper可以用來干什么旁赊?我們將如何使用Zookeeper桦踊?Zookeeper又是怎么實現(xiàn)的?
什么是Zookeeper
在Zookeeper的官網(wǎng)上有這么一句話:ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services终畅。
這大概描述了Zookeeper主要是一個分布式服務(wù)協(xié)調(diào)框架籍胯,實現(xiàn)同步服務(wù),配置維護和命名服務(wù)等分布式應(yīng)用离福。是一個高性能的分布式數(shù)據(jù)一致性解決方案杖狼。
通俗地講,ZooKeeper是動物園管理員妖爷,它是拿來管大象 Hadoop蝶涩、鯨魚 HBase、Kafka等的管理員。
Zookeeper和CAP的關(guān)系
作為一個分布式系統(tǒng)绿聘,分區(qū)容錯性是一個必須要考慮的關(guān)鍵點嗽上。一個分布式系統(tǒng)一旦喪失了分區(qū)容錯性,也就表示放棄了擴展性熄攘。因為在分布式系統(tǒng)中兽愤,網(wǎng)絡(luò)故障是經(jīng)常出現(xiàn)的,一旦出現(xiàn)在這種問題就會導致整個系統(tǒng)不可用是絕對不能容忍的挪圾。所以浅萧,大部分分布式系統(tǒng)都會在保證分區(qū)容錯性的前提下在一致性和可用性之間做權(quán)衡。
ZooKeeper是個CP(一致性+分區(qū)容錯性)的哲思,即任何時刻對ZooKeeper的訪問請求能得到一致的數(shù)據(jù)結(jié)果惯殊,同時系統(tǒng)對網(wǎng)絡(luò)分割具備容錯性;但是它不能保證每次服務(wù)請求的可用性也殖。也就是在極端環(huán)境下,ZooKeeper可能會丟棄一些請求务热,消費者程序需要重新請求才能獲得結(jié)果忆嗜。
ZooKeeper是分布式協(xié)調(diào)服務(wù),它的職責是保證數(shù)據(jù)在其管轄下的所有服務(wù)之間保持同步崎岂、一致捆毫;所以就不難理解為什么ZooKeeper被設(shè)計成CP而不是AP特性的了。而且冲甘, 作為ZooKeeper的核心實現(xiàn)算法Zab绩卤,就是解決了分布式系統(tǒng)下數(shù)據(jù)如何在多個服務(wù)之間保持同步問題的。
Zookeeper節(jié)點特性及節(jié)點屬性分析
Zookeeper提供基于類似于文件系統(tǒng)的目錄節(jié)點樹方式的數(shù)據(jù)存儲江醇,但是Zookeeper并不是用來專門存儲數(shù)據(jù)的濒憋,它的作用主要是用來維護和監(jiān)控你存儲的數(shù)據(jù)的狀態(tài)變化。通過監(jiān)控這些數(shù)據(jù)狀態(tài)的變化陶夜,從而可以達到基于數(shù)據(jù)的集群管理凛驮。
數(shù)據(jù)模型
與Linux文件系統(tǒng)不同的是,Linux文件系統(tǒng)有目錄和文件的區(qū)別条辟,而Zookeeper的數(shù)據(jù)節(jié)點稱為ZNode黔夭,ZNode是Zookeeper中數(shù)據(jù)的最小單元,每個ZNode都可以保存數(shù)據(jù)羽嫡,同時還可以掛載子節(jié)點本姥,因此構(gòu)成了一個層次化的命名空間,稱為樹杭棵。
Zookeeper中ZNode的節(jié)點創(chuàng)建時候是可以指定類型的婚惫,主要有下面幾種類型。
PERSISTENT:持久化ZNode節(jié)點,一旦創(chuàng)建這個ZNode點存儲的數(shù)據(jù)不會主動消失辰妙,除非是客戶端主動的delete鹰祸。
EPHEMERAL:臨時ZNode節(jié)點,Client連接到Zookeeper Service的時候會建立一個Session密浑,之后用這個Zookeeper連接實例創(chuàng)建該類型的znode蛙婴,一旦Client關(guān)閉了Zookeeper的連接,服務(wù)器就會清除Session尔破,然后這個Session建立的ZNode節(jié)點都會從命名空間消失街图。總結(jié)就是懒构,這個類型的znode的生命周期是和Client建立的連接一樣的餐济。
PERSISTENT_SEQUENTIAL:順序自動編號的ZNode節(jié)點,這種znoe節(jié)點會根據(jù)當前已近存在的ZNode節(jié)點編號自動加 1胆剧,而且不會隨Session斷開而消失絮姆。
EPEMERAL_SEQUENTIAL:臨時自動編號節(jié)點,ZNode節(jié)點編號會自動增加秩霍,但是會隨Session消失而消失
Watcher數(shù)據(jù)變更通知
Zookeeper使用Watcher機制實現(xiàn)分布式數(shù)據(jù)的發(fā)布/訂閱功能篙悯。
Zookeeper的Watcher機制主要包括客戶端線程、客戶端WatcherManager铃绒、Zookeeper服務(wù)器三部分鸽照。客戶端在向Zookeeper服務(wù)器注冊的同時颠悬,會將Watcher對象存儲在客戶端的WatcherManager當中矮燎。當Zookeeper服務(wù)器觸發(fā)Watcher事件后,會向客戶端發(fā)送通知赔癌,客戶端線程從WatcherManager中取出對應(yīng)的Watcher對象來執(zhí)行回調(diào)邏輯诞外。
ACL保障數(shù)據(jù)的安全
Zookeeper內(nèi)部存儲了分布式系統(tǒng)運行時狀態(tài)的元數(shù)據(jù),這些元數(shù)據(jù)會直接影響基于Zookeeper進行構(gòu)造的分布式系統(tǒng)的運行狀態(tài)灾票,如何保障系統(tǒng)中數(shù)據(jù)的安全浅乔,從而避免因誤操作而帶來的數(shù)據(jù)隨意變更而導致的數(shù)據(jù)庫異常十分重要,Zookeeper提供了一套完善的ACL權(quán)限控制機制來保障數(shù)據(jù)的安全铝条。
我們可以從三個方面來理解ACL機制:權(quán)限模式 Scheme靖苇、授權(quán)對象 ID、權(quán)限 Permission班缰,通常使用"scheme:id:permission"來標識一個有效的ACL信息贤壁。
內(nèi)存數(shù)據(jù)
Zookeeper的數(shù)據(jù)模型是樹結(jié)構(gòu),在內(nèi)存數(shù)據(jù)庫中埠忘,存儲了整棵樹的內(nèi)容脾拆,包括所有的節(jié)點路徑馒索、節(jié)點數(shù)據(jù)、ACL信息名船,Zookeeper會定時將這個數(shù)據(jù)存儲到磁盤上绰上。
DataTree:DataTree是內(nèi)存數(shù)據(jù)存儲的核心,是一個樹結(jié)構(gòu)渠驼,代表了內(nèi)存中一份完整的數(shù)據(jù)蜈块。DataTree不包含任何與網(wǎng)絡(luò)、客戶端連接及請求處理相關(guān)的業(yè)務(wù)邏輯迷扇,是一個獨立的組件百揭。
DataNode:DataNode是數(shù)據(jù)存儲的最小單元,其內(nèi)部除了保存了結(jié)點的數(shù)據(jù)內(nèi)容蜓席、ACL列表器一、節(jié)點狀態(tài)之外,還記錄了父節(jié)點的引用和子節(jié)點列表兩個屬性厨内,其也提供了對子節(jié)點列表進行操作的接口祈秕。
ZKDatabase:Zookeeper的內(nèi)存數(shù)據(jù)庫,管理Zookeeper的所有會話雏胃、DataTree存儲和事務(wù)日志踢步。ZKDatabase會定時向磁盤dump快照數(shù)據(jù),同時在Zookeeper啟動時丑掺,會通過磁盤的事務(wù)日志和快照文件恢復(fù)成一個完整的內(nèi)存數(shù)據(jù)庫。
Zookeeper的實現(xiàn)原理分析
1. Zookeeper Service網(wǎng)絡(luò)結(jié)構(gòu)
Zookeeper的工作集群可以簡單分成兩類述雾,一個是Leader街州,唯一一個,其余的都是follower玻孟,如何確定Leader是通過內(nèi)部選舉確定的唆缴。
Leader和各個follower是互相通信的,對于Zookeeper系統(tǒng)的數(shù)據(jù)都是保存在內(nèi)存里面的黍翎,同樣也會備份一份在磁盤上。
如果Leader掛了,Zookeeper集群會重新選舉政供,在毫秒級別就會重新選舉出一個Leader雄家。
集群中除非有一半以上的Zookeeper節(jié)點掛了,Zookeeper Service才不可用碰酝。
2. Zookeeper讀寫數(shù)據(jù)
寫數(shù)據(jù)霎匈,一個客戶端進行寫數(shù)據(jù)請求時,如果是follower接收到寫請求送爸,就會把請求轉(zhuǎn)發(fā)給Leader铛嘱,Leader通過內(nèi)部的Zab協(xié)議進行原子廣播暖释,直到所有Zookeeper節(jié)點都成功寫了數(shù)據(jù)后(內(nèi)存同步以及磁盤更新),這次寫請求算是完成墨吓,然后Zookeeper Service就會給Client發(fā)回響應(yīng)球匕。
讀數(shù)據(jù),因為集群中所有的Zookeeper節(jié)點都呈現(xiàn)一個同樣的命名空間視圖(就是結(jié)構(gòu)數(shù)據(jù))帖烘,上面的寫請求已經(jīng)保證了寫一次數(shù)據(jù)必須保證集群所有的Zookeeper節(jié)點都是同步命名空間的亮曹,所以讀的時候可以在任意一臺Zookeeper節(jié)點上。
3. Zookeeper工作原理
Zab協(xié)議
Zookeeper的核心是廣播蚓让,這個機制保證了各個Server之間的同步乾忱。實現(xiàn)這個機制的協(xié)議叫做Zab協(xié)議。
Zab(ZooKeeper Atomic Broadcast)原子消息廣播協(xié)議作為數(shù)據(jù)一致性的核心算法历极,Zab協(xié)議是專為Zookeeper設(shè)計的支持崩潰恢復(fù)原子消息廣播算法窄瘟。
Zab協(xié)議核心如下:
所有的事務(wù)請求必須一個全局唯一的服務(wù)器(Leader)來協(xié)調(diào)處理,集群其余的服務(wù)器稱為follower服務(wù)器趟卸。Leader服務(wù)器負責將一個客戶端請求轉(zhuǎn)化為事務(wù)提議(Proposal)蹄葱,并將該proposal分發(fā)給集群所有的follower服務(wù)器。之后Leader服務(wù)器需要等待所有的follower服務(wù)器的反饋锄列,一旦超過了半數(shù)的follower服務(wù)器進行了正確反饋后图云,那么Leader服務(wù)器就會再次向所有的follower服務(wù)器分發(fā)commit消息,要求其將前一個proposal進行提交邻邮。
Zab模式
Zab協(xié)議包括兩種基本的模式:崩潰恢復(fù)和消息廣播竣况。
當整個服務(wù)框架啟動過程中或Leader服務(wù)器出現(xiàn)網(wǎng)絡(luò)中斷、崩潰退出與重啟等異常情況時筒严,Zab協(xié)議就會進入恢復(fù)模式并選舉產(chǎn)生新的Leader服務(wù)器丹泉。
當選舉產(chǎn)生了新的Leader服務(wù)器,同時集群中已經(jīng)有過半的機器與該Leader服務(wù)器完成了狀態(tài)同步之后鸭蛙,Zab協(xié)議就會退出恢復(fù)模式摹恨,狀態(tài)同步是指數(shù)據(jù)同步,用來保證集群在過半的機器能夠和Leader服務(wù)器的數(shù)據(jù)狀態(tài)保持一致娶视。
當集群中已經(jīng)有過半的Follower服務(wù)器完成了和Leader服務(wù)器的狀態(tài)同步晒哄,那么整個服務(wù)框架就可以進入消息廣播模式。
當一臺同樣遵守Zab協(xié)議的服務(wù)器啟動后加入到集群中肪获,如果此時集群中已經(jīng)存在一個Leader服務(wù)器在負責進行消息廣播寝凌,那么加入的服務(wù)器就會自覺地進入數(shù)據(jù)恢復(fù)模式:找到Leader所在的服務(wù)器,并與其進行數(shù)據(jù)同步孝赫,然后一起參與到消息廣播流程中去硫兰。
Zookeeper只允許唯一的一個Leader服務(wù)器來進行事務(wù)請求的處理,Leader服務(wù)器在接收到客戶端的事務(wù)請求后寒锚,會生成對應(yīng)的事務(wù)提議并發(fā)起一輪廣播協(xié)議劫映,而如果集群中的其他機器收到客戶端的事務(wù)請求后违孝,那么這些非Leader服務(wù)器會首先將這個事務(wù)請求轉(zhuǎn)發(fā)給Leader服務(wù)器。
消息廣播
Zab協(xié)議的消息廣播過程使用是一個原子廣播協(xié)議泳赋,類似一個2PC提交過程雌桑。具體的:
ZooKeeper使用單一主進程Leader用于處理客戶端所有事務(wù)請求,并采用Zab的原子廣播協(xié)議祖今,將服務(wù)器數(shù)據(jù)狀態(tài)變更以事務(wù)Proposal的形式廣播Follower上校坑,因此能很好的處理客戶端的大量并發(fā)請求。
另一方面千诬,由于事務(wù)間可能存在著依賴關(guān)系耍目,Zab協(xié)議保證Leader廣播的變更序列被順序的處理,有些狀態(tài)的變更必須依賴于比它早生成的那些狀態(tài)變更徐绑。
最后邪驮,考慮到主進程Leader在任何時候可能崩潰或者異常退出, 因此Zab協(xié)議還要Leader進程崩潰的時候可以重新選出Leader并且保證數(shù)據(jù)的完整性傲茄;Follower收到Proposal后毅访,寫到磁盤,返回Ack盘榨。Leader收到大多數(shù)ACK后喻粹,廣播Commit消息,自己也提交該消息草巡。Follower收到Commit之后守呜,提交該消息。
Zab協(xié)議簡化了2PC事務(wù)提交:
去除中斷邏輯移除山憨,follower要么ack查乒,要么拋棄Leader。
Leader不需要所有的Follower都響應(yīng)成功萍歉,只要一個多數(shù)派Ack即可。
崩潰恢復(fù)
上面我們講了Zab協(xié)議在正常情況下的消息廣播過程档桃,那么一旦Leader服務(wù)器出現(xiàn)崩潰或者與過半的follower服務(wù)器失去聯(lián)系枪孩,就進入崩潰恢復(fù)模式。
恢復(fù)模式需要重新選舉出一個新的Leader藻肄,讓所有的Server都恢復(fù)到一個正確的狀態(tài)蔑舞。
Zookeeper實踐,共享鎖嘹屯,Leader選舉
分布式鎖用于控制分布式系統(tǒng)之間同步訪問共享資源的一種方式攻询,可以保證不同系統(tǒng)訪問一個或一組資源時的一致性,主要分為排它鎖和共享鎖州弟。
排它鎖又稱為寫鎖或獨占鎖钧栖,若事務(wù)T1對數(shù)據(jù)對象O1加上了排它鎖低零,那么在整個加鎖期間,只允許事務(wù)T1對O1進行讀取和更新操作拯杠,其他任何事務(wù)都不能再對這個數(shù)據(jù)對象進行任何類型的操作掏婶,直到T1釋放了排它鎖。
共享鎖又稱為讀鎖潭陪,若事務(wù)T1對數(shù)據(jù)對象O1加上共享鎖雄妥,那么當前事務(wù)只能對O1進行讀取操作,其他事務(wù)也只能對這個數(shù)據(jù)對象加共享鎖依溯,直到該數(shù)據(jù)對象上的所有共享鎖都被釋放老厌。
推薦文章:基于Zk實現(xiàn)分布式鎖
Leader選舉
Leader選舉是保證分布式數(shù)據(jù)一致性的關(guān)鍵所在。當Zookeeper集群中的一臺服務(wù)器出現(xiàn)以下兩種情況之一時黎炉,需要進入Leader選舉枝秤。
服務(wù)器初始化啟動。
服務(wù)器運行期間無法和Leader保持連接拜隧。
Zookeeper在3.4.0版本后只保留了TCP版本的 FastLeaderElection 選舉算法宿百。當一臺機器進入Leader選舉時,當前集群可能會處于以下兩種狀態(tài):
集群中已存在Leader洪添。
集群中不存在Leader垦页。
對于集群中已經(jīng)存在Leader而言,此種情況一般都是某臺機器啟動得較晚干奢,在其啟動之前痊焊,集群已經(jīng)在正常工作,對這種情況忿峻,該機器試圖去選舉Leader時薄啥,會被告知當前服務(wù)器的Leader信息,對于該機器而言逛尚,僅僅需要和Leader機器建立起連接垄惧,并進行狀態(tài)同步即可。
而在集群中不存在Leader情況下則會相對復(fù)雜绰寞,其步驟如下:
(1) 第一次投票到逊。無論哪種導致進行Leader選舉,集群的所有機器都處于試圖選舉出一個Leader的狀態(tài)滤钱,即LOOKING狀態(tài)觉壶,LOOKING機器會向所有其他機器發(fā)送消息,該消息稱為投票件缸。投票中包含了SID(服務(wù)器的唯一標識)和ZXID(事務(wù)ID)铜靶,(SID, ZXID)形式來標識一次投票信息。假定Zookeeper由5臺機器組成他炊,SID分別為1争剿、2已艰、3、4秒梅、5旗芬,ZXID分別為9、9捆蜀、9疮丛、8、8辆它,并且此時SID為2的機器是Leader機器誊薄,某一時刻,1锰茉、2所在機器出現(xiàn)故障呢蔫,因此集群開始進行Leader選舉。在第一次投票時飒筑,每臺機器都會將自己作為投票對象片吊,于是SID為3、4协屡、5的機器投票情況分別為(3, 9)俏脊,(4, 8), (5, 8)肤晓。
(2) 變更投票爷贫。每臺機器發(fā)出投票后,也會收到其他機器的投票补憾,每臺機器會根據(jù)一定規(guī)則來處理收到的其他機器的投票漫萄,并以此來決定是否需要變更自己的投票,這個規(guī)則也是整個Leader選舉算法的核心所在盈匾,其中術(shù)語描述如下
vote_sid:接收到的投票中所推舉Leader服務(wù)器的SID腾务。
vote_zxid:接收到的投票中所推舉Leader服務(wù)器的ZXID。
self_sid:當前服務(wù)器自己的SID削饵。
self_zxid:當前服務(wù)器自己的ZXID岩瘦。
每次對收到的投票的處理,都是對(vote_sid, vote_zxid)和(self_sid, self_zxid)對比的過程葵孤。
規(guī)則一:如果vote_zxid大于self_zxid担钮,就認可當前收到的投票橱赠,并再次將該投票發(fā)送出去尤仍。
規(guī)則二:如果vote_zxid小于self_zxid,那么堅持自己的投票狭姨,不做任何變更宰啦。
規(guī)則三:如果vote_zxid等于self_zxid苏遥,那么就對比兩者的SID,如果vote_sid大于self_sid赡模,那么就認可當前收到的投票田炭,并再次將該投票發(fā)送出去。
規(guī)則四:如果vote_zxid等于self_zxid漓柑,并且vote_sid小于self_sid教硫,那么堅持自己的投票,不做任何變更辆布。
結(jié)合上面規(guī)則瞬矩,給出下面的集群變更過程。
(3) 確定Leader锋玲。經(jīng)過第二輪投票后景用,集群中的每臺機器都會再次接收到其他機器的投票,然后開始統(tǒng)計投票惭蹂,如果一臺機器收到了超過半數(shù)的相同投票伞插,那么這個投票對應(yīng)的SID機器即為Leader。此時Server3將成為Leader盾碗。
由上面規(guī)則可知媚污,通常那臺服務(wù)器上的數(shù)據(jù)越新(ZXID會越大),其成為Leader的可能性越大置尔,也就越能夠保證數(shù)據(jù)的恢復(fù)杠步。如果ZXID相同,則SID越大機會越大榜轿。