ZooKeeper的Znode剖析


在ZooKeeper中,節點也稱為znode。由於對於程序員來說,對zk的操作主要是對znode的操作,因此,有必要對znode進行深入的了解。 
ZooKeeper采用了類似文件系統的的數據模型,其節點構成了一個具有層級關系的樹狀結構。例如,圖1展示了zk節點的層級樹狀結構。

這里寫圖片描述 
圖1:ZooKeeper的層級樹狀結構

圖1中,根節點 / 包含了兩個字節點 /module1,/module2,而節點 /module1 又包含了三個字節點 /module1/app1,/module1/app2,/module1/app3。在zk中,節點以絕對路徑表示,不存在相對路徑,且路徑最后不能以 / 結尾(根節點除外)。

類型

根據節點的存活時間,可以對節點划分為持久節點和臨時節點。節點的類型在創建時就被確定下來,並且不能改變。 
持久節點的存活時間不依賴於客戶端會話,只有客戶端在顯式執行刪除節點操作時,節點才消失。 
臨時節點的存活時間依賴於客戶端會話,當會話結束,臨時節點將會被自動刪除(當然也可以手動刪除臨時節點)。利用臨時節點的這一特性,我們可以使用臨時節點來進行集群管理,包括發現服務的上下線等。 
ZooKeeper規定,臨時節點不能擁有子節點。

持久節點

使用命令create可以創建一個持久節點。

create /module1 module1

這樣,便創建了一個持久節點/module1,且其數據為”module1”。

臨時節點

使用create命令,並加上-e參數,可以創建一個臨時節點。

create -e /module1/app1 app1

這樣,便創建了一個臨時節點 /module1/app1,數據為”app1”。關閉會話,然后輸入命令:

get /module1/app1

可以看到有以下提示,說明臨時節點已經被刪除。

Node does not exist: /module1/app1

順序節點

ZooKeeper中還提供了一種順序節點的節點類型。每次創建順序節點時,zk都會在路徑后面自動添加上10位的數字(計數器),例如 < path >0000000001,< path >0000000002,……這個計數器可以保證在同一個父節點下是唯一的。在zk內部使用了4個字節的有符號整形來表示這個計數器,也就是說當計數器的大小超過2147483647時,將會發生溢出。 
順序節點為節點的一種特性,也就是,持久節點和臨時節點都可以設置為順序節點。這樣一來,znode一共有4種類型:持久的、臨時的,持久順序的,臨時順序的。

使用命令create加上-s參數,可以創建順序節點,例如,

create -s /module1/app app

輸出:

Created /module1/app0000000001

便創建了一個持久順序節點 /module1/app0000000001。如果再執行此命令,則會生成節點 /module1/app0000000002。 
如果在create -s再添加-e參數,則可以創建一個臨時順序節點。

節點的數據

在創建節點時,可以指定節點中存儲的數據。ZooKeeper保證讀和寫都是原子操作,且每次讀寫操作都是對數據的完整讀取或完整寫入,並不提供對數據進行部分讀取或者寫入的操作。 
以下命令創建一個節點/module1/app2,且其存儲的數據為app2。

create /module1/app2 app2

ZooKeeper雖然提供了在節點存儲數據的功能,但它並不將自己定位為一個通用的數據庫,也就是說,你不應該在節點存儲過多的數據。Zk規定節點的數據大小不能超過1M,但實際上我們在znode的數據量應該盡可能小,因為數據過大會導致zk的性能明顯下降。如果確實需要存儲大量的數據,一般解決方法是在另外的分布式數據庫(例如Redis)中保存這部分數據,然后在znode中我們只保留這個數據庫中保存位置的索引即可。

節點的屬性

每個znode都包含了一系列的屬性,通過命令get,我們可以獲得節點的屬性。

get /module1/app2 
app2 
cZxid = 0x20000000e 
ctime = Thu Jun 30 20:41:55 HKT 2016 
mZxid = 0x20000000e 
mtime = Thu Jun 30 20:41:55 HKT 2016 
pZxid = 0x20000000e 
cversion = 0 
dataVersion = 0 
aclVersion = 0 
ephemeralOwner = 0x0 
dataLength = 4 
numChildren = 0

版本號

對於每個znode來說,均存在三個版本號:

  • dataVersion 
    數據版本號,每次對節點進行set操作,dataVersion的值都會增加1(即使設置的是相同的數據)。
  • cversion 
    子節點的版本號。當znode的子節點有變化時,cversion 的值就會增加1。
  • aclVersion 
    ACL的版本號,關於znode的ACL(Access Control List,訪問控制),可以參考 參考資料1 有關ACL的描述。

以數據版本號來說明zk中版本號的作用。每一個znode都有一個數據版本號,它隨着每次數據變化而自增。ZooKeeper提供的一些API例如setData和delete根據版本號有條件地執行。多個客戶端對同一個znode進行操作時,版本號的使用就會顯得尤為重要。例如,假設客戶端C1對znode /config寫入一些配置信息,如果另一個客戶端C2同時更新了這個znode,此時C1的版本號已經過期,C1調用setData一定不會成功。這正是版本機制有效避免了數據更新時出現的先后順序問題。在這個例子中,C1在寫入數據時使用的版本號無法匹配,使得操作失敗。圖2描述了這個情況。

這里寫圖片描述

圖2:使用版本號來阻止並行操作的不一致性

事務ID

對於zk來說,每次的變化都會產生一個唯一的事務id,zxid(ZooKeeper Transaction Id)。通過zxid,可以確定更新操作的先后順序。例如,如果zxid1小於zxid2,說明zxid1操作先於zxid2發生。 
需要指出的是,zxid對於整個zk都是唯一的,即使操作的是不同的znode。

  • cZxid 
    Znode創建的事務id。

  • mZxid 
    Znode被修改的事務id,即每次對znode的修改都會更新mZxid。

這里寫圖片描述 
圖3:Zxid在客戶端重連中的作用

在集群模式下,客戶端有多個服務器可以連接,當嘗試連接到一個不同的服務器時,這個服務器的狀態要與最后連接的服務器的狀態要保持一致。Zk正是使用zxid來標識這個狀態,圖3描述了客戶端在重連情況下zxid的作用。當客戶端因超時與S1斷開連接后,客戶端開始嘗試連接S2,但S2延遲於客戶端所識別的狀態。然而,S3的狀態與客戶端所識別的狀態一致,所以客戶端可以安全連接上S3。

時間戳

包括znode的創建時間和修改時間,創建時間是znode創建時的時間,創建后就不會改變;修改時間在每次更新znode時都會發生變化。

以下命令創建了一個 /module2 節點。

create /module2 module2 
Created /module2

通過 get 命令,可以看到 /module2的 ctime和mtime均為Sat Jul 02 11:18:32 CST 2016。

get /module2 
module2 
cZxid = 0x2 
ctime = Sat Jul 02 11:18:32 CST 2016 
mZxid = 0x2 
mtime = Sat Jul 02 11:18:32 CST 2016 
pZxid = 0x2 
cversion = 0 
dataVersion = 0 
aclVersion = 0 
ephemeralOwner = 0x0 
dataLength = 7 
numChildren = 0

修改 /module2,可以看到 ctime 沒有發生變化,mtime已更新為最新的時間。

set /module2 module2_1 
cZxid = 0x2 
ctime = Sat Jul 02 11:18:32 CST 2016 
mZxid = 0x3 
mtime = Sat Jul 02 11:18:50 CST 2016 
pZxid = 0x2 
cversion = 0 
dataVersion = 1 
aclVersion = 0 
ephemeralOwner = 0x0 
dataLength = 9 
numChildren = 0

參考資料

    1. http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#ch_zkDataModel
    2. http://java.globinch.com/enterprise-services/zookeeper/apache-zookeeper-explained-tutorial-cases-zookeeper-java-api-examples/#
    3. 《ZooKeeper分布式過程協同技術詳解》,Flavio Junqueira等著,謝超等譯


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM