摘要:除此之外,它嚴格的序列訪問控制意味著復雜的控制原語可以應用在客戶端上。版本號對節(jié)點的每一個操作都將致使這個節(jié)點的版本號增加。事件是一次性的觸發(fā)器,當?shù)膶ο鬆顟B(tài)發(fā)生改變時,將會觸發(fā)此對象上所對應的事件。節(jié)點事件節(jié)點的建立,刪除,數(shù)據(jù)的修改。
目錄
一、ZooKeeper概述
二、ZooKeeper數(shù)據(jù)模型
三、ZooKeeper服務中操作
四、Watch觸發(fā)器
五、ZooKeeper應用舉例
一、ZooKeeper概述ZooKeeper是一種為分布式應用所設計的高可用、高性能且一致的開源協(xié)調服務,它提供了一項基本服務:分布式鎖服務。由于ZooKeeper的開源特性,后來我們的開發(fā)者在分布式鎖的基礎上,摸索了出了其他的使用方法:配置維護、組服務、分布式消息隊列、分布式通知/協(xié)調等。
注意:ZooKeeper性能上的特點決定了它能夠用在大型的、分布式的系統(tǒng)當中。從可靠性方面來說,它并不會因為一個節(jié)點的錯誤而崩潰。除此之外,它嚴格的序列訪問控制意味著復雜的控制原語可以應用在客戶端上。ZooKeeper在一致性、可用性、容錯性的保證,也是ZooKeeper的成功之處,它獲得的一切成功都與它采用的協(xié)議——Zab協(xié)議是密不可分的,這些內容將會在后面介紹。
前面提到了那么多的服務,比如分布式鎖、配置維護、組服務等,那它們是如何實現(xiàn)的呢,我相信這才是大家關心的東西。ZooKeeper在實現(xiàn)這些服務時,首先它設計一種新的數(shù)據(jù)結構——Znode,然后在該數(shù)據(jù)結構的基礎上定義了一些原語,也就是一些關于該數(shù)據(jù)結構的一些操作。有了這些數(shù)據(jù)結構和原語還不夠,因為我們的ZooKeeper是工作在一個分布式的環(huán)境下,我們的服務是通過消息以網(wǎng)絡的形式發(fā)送給我們的分布式應用程序,所以還需要一個通知機制——Watcher機制。那么總結一下,ZooKeeper所提供的服務主要是通過:數(shù)據(jù)結構+原語+watcher機制,三個部分來實現(xiàn)的。那么我就從這三個方面,給大家介紹一下ZooKeeper。
二、ZooKeeper數(shù)據(jù)模型2.1 ZooKeeper數(shù)據(jù)模型Znode
ZooKeeper擁有一個層次的命名空間,這個和標準的文件系統(tǒng)非常相似,如下圖2.1、2.2 所示。
從圖中我們可以看出ZooKeeper的數(shù)據(jù)模型,在結構上和標準文件系統(tǒng)的非常相似,都是采用這種樹形層次結構,ZooKeeper樹中的每個節(jié)點被稱為—Znode。和文件系統(tǒng)的目錄樹一樣,ZooKeeper樹中的每個節(jié)點可以擁有子節(jié)點。但也有不同之處:
(1) 引用方式
Zonde通過路徑引用,如同Unix中的文件路徑。路徑必須是絕對的,因此他們必須由斜杠字符來開頭。除此以外,他們必須是唯一的,也就是說每一個路徑只有一個表示,因此這些路徑不能改變。在ZooKeeper中,路徑由Unicode字符串組成,并且有一些限制。字符串"/zookeeper"用以保存管理信息,比如關鍵配額信息。
(2) Znode結構
ZooKeeper命名空間中的Znode,兼具文件和目錄兩種特點。既像文件一樣維護著數(shù)據(jù)、元信息、ACL、時間戳等數(shù)據(jù)結構,又像目錄一樣可以作為路徑標識的一部分。圖中的每個節(jié)點稱為一個Znode。 每個Znode由3部分組成:
① stat:此為狀態(tài)信息, 描述該Znode的版本, 權限等信息
② data:與該Znode關聯(lián)的數(shù)據(jù)
③ children:該Znode下的子節(jié)點
ZooKeeper雖然可以關聯(lián)一些數(shù)據(jù),但并沒有被設計為常規(guī)的數(shù)據(jù)庫或者大數(shù)據(jù)存儲,相反的是,它用來管理調度數(shù)據(jù),比如分布式應用中的配置文件信息、狀態(tài)信息、匯集位置等等。這些數(shù)據(jù)的共同特性就是它們都是很小的數(shù)據(jù),通常以KB為大小單位。ZooKeeper的服務器和客戶端都被設計為嚴格檢查并限制每個Znode的數(shù)據(jù)大小至多1M,但常規(guī)使用中應該遠小于此值。
(3) 數(shù)據(jù)訪問
ZooKeeper中的每個節(jié)點存儲的數(shù)據(jù)要被原子性的操作。也就是說讀操作將獲取與節(jié)點相關的所有數(shù)據(jù),寫操作也將替換掉節(jié)點的所有數(shù)據(jù)。另外,每一個節(jié)點都擁有自己的ACL(訪問控制列表),這個列表規(guī)定了用戶的權限,即限定了特定用戶對目標節(jié)點可以執(zhí)行的操作。
(4) 節(jié)點類型
ZooKeeper中的節(jié)點有兩種,分別為臨時節(jié)點和永久節(jié)點。節(jié)點的類型在創(chuàng)建時即被確定,并且不能改變。
① 臨時節(jié)點:該節(jié)點的生命周期依賴于創(chuàng)建它們的會話。一旦會話(Session)結束,臨時節(jié)點將被自動刪除,當然可以也可以手動刪除。雖然每個臨時的Znode都會綁定到一個客戶端會話,但他們對所有的客戶端還是可見的。另外,ZooKeeper的臨時節(jié)點不允許擁有子節(jié)點。
② 永久節(jié)點:該節(jié)點的生命周期不依賴于會話,并且只有在客戶端顯示執(zhí)行刪除操作的時候,他們才能被刪除。
(5) 順序節(jié)點
當創(chuàng)建Znode的時候,用戶可以請求在ZooKeeper的路徑結尾添加一個遞增的計數(shù)。這個計數(shù)對于此節(jié)點的父節(jié)點來說是唯一的,它的格式為"%10d"(10位數(shù)字,沒有數(shù)值的數(shù)位用0補充,例如"0000000001")。當計數(shù)值大于232-1時,計數(shù)器將溢出。
(6) 觀察
客戶端可以在節(jié)點上設置watch,我們稱之為監(jiān)視器。當節(jié)點狀態(tài)發(fā)生改變時(Znode的增、刪、改)將會觸發(fā)watch所對應的操作。當watch被觸發(fā)時,ZooKeeper將會向客戶端發(fā)送且僅發(fā)送一條通知,因為watch只能被觸發(fā)一次,這樣可以減少網(wǎng)絡流量。
2.2 ZooKeeper中的時間
ZooKeeper有多種記錄時間的形式,其中包含以下幾個主要屬性:
(1) Zxid
致使ZooKeeper節(jié)點狀態(tài)改變的每一個操作都將使節(jié)點接收到一個Zxid格式的時間戳,并且這個時間戳全局有序。也就是說,也就是說,每個對節(jié)點的改變都將產生一個唯一的Zxid。如果Zxid1的值小于Zxid2的值,那么Zxid1所對應的事件發(fā)生在Zxid2所對應的事件之前。實際上,ZooKeeper的每個節(jié)點維護者三個Zxid值,為別為:cZxid、mZxid、pZxid。
① cZxid: 是節(jié)點的創(chuàng)建時間所對應的Zxid格式時間戳。
② mZxid:是節(jié)點的修改時間所對應的Zxid格式時間戳。
實現(xiàn)中Zxid是一個64為的數(shù)字,它高32位是epoch用來標識leader關系是否改變,每次一個leader被選出來,它都會有一個 新的epoch。低32位是個遞增計數(shù)。 (2) 版本號
對節(jié)點的每一個操作都將致使這個節(jié)點的版本號增加。每個節(jié)點維護著三個版本號,他們分別為:
① version:節(jié)點數(shù)據(jù)版本號
② cversion:子節(jié)點版本號
③ aversion:節(jié)點所擁有的ACL版本號
2.3 ZooKeeper節(jié)點屬性
通過前面的介紹,我們可以了解到,一個節(jié)點自身擁有表示其狀態(tài)的許多重要屬性,如下圖所示。
三、ZooKeeper服務中操作在ZooKeeper中有9個基本操作,如下圖所示:
更新ZooKeeper操作是有限制的。delete或setData必須明確要更新的Znode的版本號,我們可以調用exists找到。如果版本號不匹配,更新將會失敗。
更新ZooKeeper操作是非阻塞式的。因此客戶端如果失去了一個更新(由于另一個進程在同時更新這個Znode),他可以在不阻塞其他進程執(zhí)行的情況下,選擇重新嘗試或進行其他操作。
盡管ZooKeeper可以被看做是一個文件系統(tǒng),但是處于便利,摒棄了一些文件系統(tǒng)地操作原語。因為文件非常的小并且使整體讀寫的,所以不需要打開、關閉或是尋地的操作。
四、Watch觸發(fā)器(1) watch概述
ZooKeeper可以為所有的讀操作設置watch,這些讀操作包括:exists()、getChildren()及getData()。watch事件是一次性的觸發(fā)器,當watch的對象狀態(tài)發(fā)生改變時,將會觸發(fā)此對象上watch所對應的事件。watch事件將被異步地發(fā)送給客戶端,并且ZooKeeper為watch機制提供了有序的一致性保證。理論上,客戶端接收watch事件的時間要快于其看到watch對象狀態(tài)變化的時間。
(2) watch類型
ZooKeeper所管理的watch可以分為兩類:
① 數(shù)據(jù)watch(data watches):getData和exists負責設置數(shù)據(jù)watch
② 孩子watch(child watches):getChildren負責設置孩子watch
我們可以通過操作返回的數(shù)據(jù)來設置不同的watch:
① getData和exists:返回關于節(jié)點的數(shù)據(jù)信息
② getChildren:返回孩子列表
因此
① 一個成功的setData操作將觸發(fā)Znode的數(shù)據(jù)watch
② 一個成功的create操作將觸發(fā)Znode的數(shù)據(jù)watch以及孩子watch
③ 一個成功的delete操作將觸發(fā)Znode的數(shù)據(jù)watch以及孩子watch
(3) watch注冊與處觸發(fā)
如圖下圖所示:
① exists操作上的watch,在被監(jiān)視的Znode創(chuàng)建、刪除或數(shù)據(jù)更新時被觸發(fā)。
② getData操作上的watch,在被監(jiān)視的Znode刪除或數(shù)據(jù)更新時被觸發(fā)。在被創(chuàng)建時不能被觸發(fā),因為只有Znode一定存在,getData操作才會成功。
③ getChildren操作上的watch,在被監(jiān)視的Znode的子節(jié)點創(chuàng)建或刪除,或是這個Znode自身被刪除時被觸發(fā)??梢酝ㄟ^查看watch事件類型來區(qū)分是Znode,還是他的子節(jié)點被刪除:NodeDelete表示Znode被刪除,NodeDeletedChanged表示子節(jié)點被刪除。
Watch由客戶端所連接的ZooKeeper服務器在本地維護,因此watch可以非常容易地設置、管理和分派。當客戶端連接到一個新的服務器時,任何的會話事件都將可能觸發(fā)watch。另外,當從服務器斷開連接的時候,watch將不會被接收。但是,當一個客戶端重新建立連接的時候,任何先前注冊過的watch都會被重新注冊。
(4) 需要注意的幾點
Zookeeper的watch實際上要處理兩類事件:
① 連接狀態(tài)事件(type=None, path=null)
這類事件不需要注冊,也不需要我們連續(xù)觸發(fā),我們只要處理就行了。
② 節(jié)點事件
節(jié)點的建立,刪除,數(shù)據(jù)的修改。它是one time trigger,我們需要不停的注冊觸發(fā),還可能發(fā)生事件丟失的情況。
上面2類事件都在Watch中處理,也就是重載的process(Event event)
節(jié)點事件的觸發(fā),通過函數(shù)exists,getData或getChildren來處理這類函數(shù),有雙重作用:
① 注冊觸發(fā)事件
② 函數(shù)本身的功能
函數(shù)的本身的功能又可以用異步的回調函數(shù)來實現(xiàn),重載processResult()過程中處理函數(shù)本身的的功能。
五、ZooKeeper應用舉例
為了方便大家理解ZooKeeper,在此就給大家舉個例子,看看ZooKeeper是如何實現(xiàn)的他的服務的,我以ZooKeeper提供的基本服務分布式鎖為例。
5.1 分布式鎖應用場景
在分布式鎖服務中,有一種最典型應用場景,就是通過對集群進行Master選舉,來解決分布式系統(tǒng)中的單點故障。什么是分布式系統(tǒng)中的單點故障:通常分布式系統(tǒng)采用主從模式,就是一個主控機連接多個處理節(jié)點。主節(jié)點負責分發(fā)任務,從節(jié)點負責處理任務,當我們的主節(jié)點發(fā)生故障時,那么整個系統(tǒng)就都癱瘓了,那么我們把這種故障叫作單點故障。如下圖5.1和5.2所示:
5.2 傳統(tǒng)解決方案
傳統(tǒng)方式是采用一個備用節(jié)點,這個備用節(jié)點定期給當前主節(jié)點發(fā)送ping包,主節(jié)點收到ping包以后向備用節(jié)點發(fā)送回復Ack,當備用節(jié)點收到回復的時候就會認為當前主節(jié)點還活著,讓他繼續(xù)提供服務。如圖5.3所示:
當主節(jié)點掛了,這時候備用節(jié)點收不到回復了,然后他就認為主節(jié)點掛了接替他成為主節(jié)點如下圖5.4所示:
但是這種方式就是有一個隱患,就是網(wǎng)絡問題,來看一網(wǎng)絡問題會造成什么后果,如下圖5.5所示:
也就是說我們的主節(jié)點的并沒有掛,只是在回復的時候網(wǎng)絡發(fā)生故障,這樣我們的備用節(jié)點同樣收不到回復,就會認為主節(jié)點掛了,然后備用節(jié)點將他的Master實例啟動起來,這樣我們的分布式系統(tǒng)當中就有了兩個主節(jié)點也就是---雙Master,出現(xiàn)Master以后我們的從節(jié)點就會將它所做的事一部分匯報給了主節(jié)點,一部分匯報給了從節(jié)點,這樣服務就全亂了。為了防止出現(xiàn)這種情況,我們引入了ZooKeeper,它雖然不能避免網(wǎng)絡故障,但它能夠保證每時每刻只有一個Master。我么來看一下ZooKeeper是如何實現(xiàn)的。
5.3 ZooKeeper解決方案
(1) Master啟動
在引入了Zookeeper以后我們啟動了兩個主節(jié)點,"主節(jié)點-A"和"主節(jié)點-B"他們啟動以后,都向ZooKeeper去注冊一個節(jié)點。我們假設"主節(jié)點-A"鎖注冊地節(jié)點是"master-00001","主節(jié)點-B"注冊的節(jié)點是"master-00002",注冊完以后進行選舉,編號最小的節(jié)點將在選舉中獲勝獲得鎖成為主節(jié)點,也就是我們的"主節(jié)點-A"將會獲得鎖成為主節(jié)點,然后"主節(jié)點-B"將被阻塞成為一個備用節(jié)點。那么,通過這種方式就完成了對兩個Master進程的調度。
圖5.6ZooKeeper Master選舉
(2) Master故障
如果"主節(jié)點-A"掛了,這時候他所注冊的節(jié)點將被自動刪除,ZooKeeper會自動感知節(jié)點的變化,然后再次發(fā)出選舉,這時候"主節(jié)點-B"將在選舉中獲勝,替代"主節(jié)點-A"成為主節(jié)點。
(3) Master 恢復
如果主節(jié)點恢復了,他會再次向ZooKeeper注冊一個節(jié)點,這時候他注冊的節(jié)點將會是"master-00003",ZooKeeper會感知節(jié)點的變化再次發(fā)動選舉,這時候"主節(jié)點-B"在選舉中會再次獲勝繼續(xù)擔任"主節(jié)點","主節(jié)點-A"會擔任備用節(jié)點。
感謝您耐心看完的文章
順便給大家推薦一個Java技術交流群:710373545里面會分享一些資深架構師錄制的視頻資料:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務架構的原理,JVM性能優(yōu)化、分布式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/74659.html
摘要:表示的是兩個,當其中任意一個計算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經常可見它的使用,在開始分析它的高并發(fā)實現(xiàn)機制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個比較典型的互聯(lián)網(wǎng)高并發(fā)場景。 干貨:深度剖析分布式搜索引擎設計 分布式,高可用,和機器學習一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個名詞,今天我們首先來說說分布式。 探究...
閱讀 1067·2021-11-22 15:35
閱讀 1703·2021-10-26 09:49
閱讀 3244·2021-09-02 15:11
閱讀 2092·2019-08-30 15:53
閱讀 2644·2019-08-30 15:53
閱讀 2940·2019-08-30 14:11
閱讀 3539·2019-08-30 12:59
閱讀 3252·2019-08-30 12:53