摘要:具有不可分割性即原語的執行必須是連續的,在執行過程中不允許被中斷。提供服務主要就是通過數據結構原語集機制達到的。子節點的版本號數據節點版本號版本號創建該節點的會話的。后位則為遞增序列。
前言
最近加入了部門的技術興趣小組,被分配了Zookeeper的研究任務。在研究過程當中,發現Zookeeper由于其開源的特性和其卓越的性能特點,在業界使用廣泛,有很多的應用場景,而這些不同的應用場景實際上底層的原理都是差不多的,只要你真正理解了Zookeeper的一些基礎概念和機制,就能夠觸類旁通。
于是乎,在第一次和項目小組內成員分享過Zookeeper作為服務注冊中心的原理和客戶端demo演示之后,我萌生出了整理一個專題的想法,以此為起點,慢慢撿起自己的博客分享之路。
本篇的內容主要介紹以下幾點:
What is Zookeeper
Zookeeper 數據模型
Zookeeper 服務基本操作
Sessions
Watches
總結
一、What is Zookeeper我最早接觸Zookeeper是因為我們項目使用的微服務治理架構是Dubbo,Dubbo推薦使用的服務注冊中心就是Zookeeper。從本質上來說,Zookeeper就是一種分布式協調服務,在分布式環境中協調和管理服務是一個復雜的過程。ZooKeeper通過其簡單的架構和API解決了這個問題。 ZooKeeper允許開發人員專注于核心應用程序邏輯,而不必擔心應用程序的分布式特性。Zookeeper最早的應用是在Hadoop生態中,Apache HBase使用ZooKeeper跟蹤分布式數據的狀態。
實際上從它的名字上就很好理解,Zoo - 動物園,Keeper - 管理員,動物園中有很多種動物,這里的動物就可以比作分布式環境下多種多樣的服務,而Zookeeper做的就是管理這些服務。
ZooKeeper 的設計目標是將那些復雜且容易出錯的分布式一致性服務封裝起來,構成一個高效可靠的原語集,并以一系列簡單易用的接口提供給用戶使用。
原語: 操作系統或計算機網絡用語范疇。是由若干條指令組成的,用于完成一定功能的一個過程。具有不可分割性·即原語的執行必須是連續的,在執行過程中不允許被中斷。
Zookeeper提供服務主要就是通過:數據結構 + 原語集 + watch機制達到的。
分布式應用程序結合Zookeeper可以實現諸如數據發布/訂閱、負載均衡、命名服務、分布式協調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等功能。
二、Zookeeper 數據模型 ZNode從上圖可以看到,Zookeeper的數據模型和Unix的文件系統目錄樹很類似,擁有一個層次的命名空間。這里面的每一個節點都被稱為 - ZNode, 節點可以擁有子節點,同時也允許少量數據節點存儲在該節點之下。(可以理解成一個允許一個文件也可以是一個目錄的文件系統)
(1)節點引用方式ZNode通過路徑引用,如同Unix中的文件路徑。路徑必須是絕對的,因此他們必須有斜杠字符/來開頭,除此之外,路徑名必須是唯一的,且不能更改。
這個特性在Dubbo的服務注冊上也有體現,Dubbo源碼中有個貫穿全局的類URL,dubbo是以總線模式來時刻傳遞和保存配置信息的,也就是配置信息都被放在URL上進行傳遞,隨時可以取得相關配置信息。Dubbo在向注冊中心注冊時寫下的節點名就是由URL中的URI和配置信息編碼后組成的。如下圖。
這屬于這部分知識的擴展內容,在之后服務注冊中心的章節會更具體的說明。
前面提到過,ZNode兼具文件和目錄兩種特點,既像文件一樣維護著數據、元信息、ACL、時間戳等數據結構,又像目錄一樣可以作為路徑標識的一部分。
ZNode由以下幾部分組成:
Stat數據結構
操作控制列表(ACL) - 每個節點都有一個ACL來做節點的操作控制,這個列表規定了用戶的權限,限定了特定用戶對目標節點的操作
CREATE - 創建子節點的權限
READ - 獲取節點數據和子節點列表的權限
WRITE - 更新節點數據的權限
DELETE - 刪除子節點的權限
ADMIN - 設置節點ACL的權限
版本 - ZNode有三個數據版本
version - 當前ZNode的版本
cversion - 當前ZNode子節點的版本
aversion - 當前ACL列表的版本
Zxid
可以理解成Zookeeper中時間戳的一種表現形式,也可以理解成事務ID的概念
如果Zxid1的值小于Zxid2的值,那么Zxid1所對應的事件發生在Zxid2所對應的事件之前。
ZooKeeper的每個節點維護者三個Zxid值,分別為:cZxid、mZxid、pZxid。
cZxid:節點創建時間 create
mZxid:節點最近一次修改時間 modify
pZxid:該節點的子節點列表最后一次被修改時的時間,子節點內容變更不會變更pZxid
data域
children節點
下面有幾個需要注意的知識點著重講一下:
A. 狀態信息/節點屬性下圖是我在服務器上使用zkClient,用get命令獲取到的某個Dubbo微服務接口節點的狀態信息,來作為示例,
[zk: localhost:2181(CONNECTED) 0] get /dubbo/com.***.microservice.ucs.api.UniqueControlApi 127.0.0.1 // 節點數據Data域 cZxid = 0xdd59 //Created ZXID,表示該ZNode被創建時的事務ID ctime = Thu Apr 18 15:17:11 CST 2019 //Created Time,表示該ZNode被創建的時間 mZxid = 0xdd59 //Modified ZXID,表示該ZNode最后一次被更新時的事務ID mtime = Thu Apr 18 15:17:11 CST 2019 //Modified Time,表示該節點最后一次被更新的時間 pZxid = 0xdd62 //表示該節點的子節點列表最后一次被修改時的事務ID。注意,只有子節點列表變更了才會變更pZxid,子節點內容變更不會影響pZxid。 cversion = 4 //子節點的版本號 dataVersion = 0 //數據節點版本號 aclVersion = 0 //ACL版本號 ephemeralOwner = 0x0 //創建該節點的會話的sessionID。如果該節點是持久節點,那么這個屬性值為0。 dataLength = 9 // Data域內容長度 numChildren = 4 // 子節點個數 眾所周知,Dubbo接口子節點分為providers/configurators/routers/consumersB. Data域
關于Data域,Zookeeper中每個節點存儲的數據要被原子性的操作,也就是說讀操作將獲取與節點相關的所有數據,寫操作也將替換掉節點的所有數據。
值得注意的是,Zookeeper雖然可以存儲數據,但是從設計目的上,并不是為了做數據庫或者大數據存儲,相反,它是用來管理調度數據,比如分布式應用中的配置文件信息、狀態信息、匯集位置等,這些數據通常是很小的數據,KB為大小單位。ZNode對數據大小也有限制,至多1M。實際上從這里,就可以推導出Zookeeper用于分布式配置中心的可行性。
C. Zxid在ZooKeeper中,能改變ZooKeeper服務器狀態的操作稱為事務操作。一般包括數據節點創建與刪除、數據內容更新和客戶端會話創建與失效等操作。對應每一個事務請求,ZooKeeper都會為其分配一個全局唯一的事務ID,用Zxid表示。
由上圖的示例可以看出,Zxid是一個64位的數字。前32位叫做epoch,用來標識Zookeeper 集群中的Leader節點,當Leader節點更換時,就會有一個新的epoch。后32位則為遞增序列。從這些Zxid中可以間接地識別出ZooKeeper處理這些事務操作請求的全局順序。
(3)節點類型ZNode節點類型嚴格來說有四種:持久節點、臨時節點、持久順序節點、臨時順序節點
PERSISTENT 持久節點 - 該節點的生命周期不依賴于session,創建之后客戶端斷開連接,節點依舊存在,只用客戶端執行刪除操作,節點才能被刪除;
EPHEMERAL 臨時節點 - 該節點的聲明周期依賴于session,客戶端斷開連接,臨時節點就會自動刪除。另外,臨時節點不允許有子節點。
SEQUENTIAL 順序節點 - 當選擇創建順序節點時,ZooKeeper通過將10位的序列號附加到原始名稱來設置znode的路徑。例如,如果將具有路徑 /myapp 的znode創建為順序節點,則ZooKeeper會將路徑更改為 /myapp0000000001 ,并將下一個序列號設置為0000000002。如果兩個順序節點是同時創建的,那么ZooKeeper不會對每個znode使用相同的數字。順序節點在鎖定和同步中起重要作用。
三、Zookeeper服務基本操作如上圖,標明了Zookeeper服務的九種基本操作,進入ZkClient.sh,使用help,可以看到這幾種操作。
[zk: localhost:2181(CONNECTED) 1] help ZooKeeper -server host:port cmd args stat path [watch] // 獲取指定節點的狀態信息 set path data [version] // setData操作 ls path [watch] // 查看某個節點下的所有子節點信息 delquota [-n|-b] path // 刪除節點配額 ls2 path [watch] // ls + stat 兩個命令結合 setAcl path acl // 設置ACL setquota -n|-b val path // 設置節點配額,-n 是限制子節點個數 -b是限制節點數據長度 history // 歷史命令 redo cmdno // 執行歷史命令 printwatches on|off delete path [version] // 刪除指定路徑節點,有子節點需要先刪除子節點 sync path // 同步視圖 listquota path // 查看節點配額信息 rmr path // 刪除節點及其子節點 get path [watch] // 獲取當前節點數據內容 create [-s] [-e] path data acl // 創建節點 addauth scheme auth quit getAcl path // 獲取ACL close connect host:port
從命令中可以看到,更新ZooKeeper操作是有限制的。delete或setData必須明確要更新的Znode的版本號,我們可以調用exists找到。如果版本號不匹配,更新將會失敗。
更新ZooKeeper操作是非阻塞式的。因此客戶端如果失去了一個更新(由于另一個進程在同時更新這個Znode),他可以在不阻塞其他進程執行的情況下,選擇重新嘗試或進行其他操作。
四、Sessions在 ZooKeeper 中,一個客戶端連接是指客戶端和服務器之間的一個 TCP 長連接。客戶端啟動的時候,首先會與服務器建立一個 TCP 連接,從第一次連接建立開始,客戶端會話的生命周期也開始了。通過這個連接,客戶端能夠通過心跳檢測與服務器保持有效的會話,也能夠向Zookeeper服務器發送請求并接受響應,同時還能夠通過該連接接收來自服務器的Watch事件通知。
客戶端以特定的時間間隔發送心跳以保持會話有效。如果ZooKeeper Server Ensembles在超過服務器開啟時指定的期間(會話超時)都沒有從客戶端接收到心跳,則它會判定客戶端死機。
會話超時通常以毫秒為單位。當會話由于任何原因結束時,在該會話期間創建的臨時節點也會被刪除。
五、Watches在我看來,Watches - 監聽事件,是Zookeeper中一個很重要的特性,也是實現Zookeeper大多數功能的核心特性之一。簡單來說, Zookeeper允許Client端在指定節點上注冊Watches,在某些特定事件觸發的時候,Zookeeper服務端會將事件異步通知到感興趣(即注冊了Watches)的客戶端上去。可以理解成一個訂閱/發布系統,是不是。
Znode更改是與znode相關的數據的修改或znode的子項中的更改。只觸發一次watches。如果客戶端想要再次通知,則必須通過另一個讀取操作來完成。當連接會話過期時,客戶端將與服務器斷開連接,相關的watches也將被刪除。
下面說完簡單的,來說點復雜的部分。
幾個特性先了解下:
One-time trigger 一次watch時間只會被觸發一遍,如果節點再次發生變化,除非之前有重新設置過watches,不然會收到通知;
Sent to Client 當watch的對象狀態發生改變時,將會觸發此對象上watch所對應的事件。watch事件將被異步地發送給客戶端,并且ZooKeeper為watch機制提供了有序的一致性保證(Ordering guarantee)。
The data for which the watch was set 發送給客戶端的數據信息,實際上就是你這個watch監視的類型,見下文介紹
Zookeeper的Watches 分為兩種,數據監聽器(Data Watches)和子節點監聽器(Children Watches)。即你可以對某個節點的Data設置watches,也可以對某個子節點設置watches。
可以看下Zookeeper Java 客戶端 Zkclient 中的設置watches的代碼:
// listener 監聽器 // path 節點路徑 // 子節點監聽器 private ListaddTargetChildListener(String path, IZkChildListener listener) { return client.subscribeChildChanges(path, listener); } // 節點數據的監聽器 public void addChildDataListener(String path, IZkDataListener listener) { try { // 遞歸創建節點 client.subscribeDataChanges(path, listener); } catch (ZkNodeExistsException e) { } }
作為開發者,需要知道監控節點的什么操作會觸發你設置的watches。
一個成功的setData操作將觸發Znode的數據watches
一個成功的create操作將觸發Znode的數據watches以及子節點watches
一個成功的delete操作將觸發Znode的數據watches和子節點watches
再看下ZkClient中的數據監聽器接口IZkDataListener
public interface IZkDataListener { // 監控節點數據更新的時候會觸發 這段邏輯 public void handleDataChange(String dataPath, Object data) throws Exception; // 監控節點被刪除的時候會觸發 這段邏輯 public void handleDataDeleted(String dataPath) throws Exception; }
再看下ZkClient中的子節點監聽器接口IZkChildListener
public interface IZkChildListener { /** * Called when the children of the given path changed. * 監控節點的子節點列表改變時會觸發這段邏輯 * * @param parentPath * The parent path * @param currentChilds * The children or null if the root node (parent path) was deleted. * @throws Exception */ public void handleChildChange(String parentPath, ListcurrentChilds) throws Exception; }
實際上看到這就能聯想到,Zookeeper是可以當做分布式配置中心來使用的,只不過你需要自己擴展他異步通知節點數據變化之后的邏輯,更新你的配置。在后面的章節會更新相關demo。
關于Watches 詳細介紹可以參考官網的介紹:
ZooKeeper Watches六、 總結https://zookeeper.apache.org/...
本章內容算是Zookeeper系列的開篇,介紹了Zookeeper的幾個基礎概念,并且給出了相關實例,助于理解。
現在我們再回過頭來看看Zookeeper的特性:
① 順序一致性
從同一個客戶端發起的事務請求,最終將會嚴格按照其發起順序被應用到ZooKeeper中。② 原子性
所有事務請求的結果在集群中所有機器上的應用情況是一致的,也就是說要么整個集群所有集群都成功應用了某一個事務,要么都沒有應用,一定不會出現集群中部分機器應用了該事務,而另外一部分沒有應用的情況。③ 單一視圖
無論客戶端連接的是哪個ZooKeeper服務器,其看到的服務端數據模型都是一致的。④ 可靠性
一旦服務端成功地應用了一個事務,并完成對客戶端的響應,那么該事務所引起的服務端狀態變更將會被一直保留下來,除非有另一個事務又對其進行了變更。⑤ 實時性
通常人們看到實時性的第一反應是,一旦一個事務被成功應用,那么客戶端能夠立即從服務端上讀取到這個事務變更后的最新數據狀態。這里需要注意的是,ZooKeeper僅僅保證在一定的時間段內,客戶端最終一定能夠從服務端上讀取到最新的數據狀態。
今天的內容中,順序一致性是通過ZXid來實現的,全局唯一,順序遞增,同一個session中請求是FIFO的;可靠性的描述也可以通過今天的知識進行理解,一次事務的應用,服務端狀態的變更會以Zxid、Znode數據版本、數據、節點路徑的形式保存下來。剩下的幾種特性是怎么實現的,在學習完Zookeeper集群相關的內容之后應該就能理解。
本篇文章中借鑒了網上幾篇優秀的文章,并且結合了我本人一些思考和實踐。希望能對你學習了解Zookeeper起到一些幫助。
下一章,我會介紹Zookeeper集群方面的知識,CAP理論在Zookeeper中的實踐,以及如何搭建Zookeeper的集群。
參考[1] https://zookeeper.apache.org/... 官方文檔(強烈推薦)
[2] https://www.cnblogs.com/sundd... 作者應該是對官方文檔有比較深的了解,我發現他的文章的脈絡和官網有很相似的地方。寫的非常好
[3] https://www.jianshu.com/p/a17... 作者對Zookeeper做了一個易懂的總體介紹
[4] https://www.w3cschool.cn/zook... w3cSchool tutorial
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74192.html
摘要:協議是為分布式協調服務專門設計的一種支持崩潰恢復的一致性協議,這個機制保證了各個之間的同步。選主是協議中最為重要和復雜的過程。以實際效果而言,分區相當于對通信的時限要求。參考官方文檔阿里巴巴為什么不用做服務發現定理的含義阮一峰 前言 同學們,在上一章中,我們主要講了Zookeeper兩種啟動模式以及具體如何搭建。本章內容主要講的是集群相關的原理內容,第一章可以當做是Zookeeper原...
摘要:之后服務器等待其他服務器的反饋,一旦超過半數的服務器進行了正確的反饋,那么就會再次向所有的服務器分發消息,要求其將前一個進行提交。協議包括兩種基本的模式,分別是崩潰恢復和消息廣播。 前言 zookeeper本質上就是一個分布式協調服務,用來解決分布式一致性的問題。 本文適合有一定分布式基礎的讀者閱讀。什么叫相關的基礎呢?起碼你得知道系統架構為何從集中式演變成了分布式,分布式有哪些優點...
摘要:表示的是兩個,當其中任意一個計算完并發編程之是線程安全并且高效的,在并發編程中經常可見它的使用,在開始分析它的高并發實現機制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個比較典型的互聯網高并發場景。 干貨:深度剖析分布式搜索引擎設計 分布式,高可用,和機器學習一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個名詞,今天我們首先來說說分布式。 探究...
閱讀 1626·2021-10-14 09:43
閱讀 5503·2021-09-07 10:21
閱讀 1275·2019-08-30 15:56
閱讀 2123·2019-08-30 15:53
閱讀 1231·2019-08-30 15:44
閱讀 2010·2019-08-30 15:44
閱讀 1320·2019-08-29 17:24
閱讀 752·2019-08-29 15:19