ZooKeeper 數據模型:節點的特性與應用


zk的基礎知識基本分為三大模塊

  • 數據模型
  • ACL 權限控制
  • Watch 監控

數據模型

默認配置文件

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
  1. tickTime client-server 通信心跳時間
    1. zk 服務器之間或client 與服務器之間維持心跳的時間間隔、也就是每個tickTime 就會發送一個心跳、tickTime 以毫秒為單位
  2. initLimit leader-follower 初始通信時限
    1. 集群中 follower 與leader 之間初始連接時最多能容忍的最多心跳數 。
  3. syncLimit leader follower 同步通信時限
    1. follower與 leader 服務器請求與應答之間能容忍的最多心跳數
  4. dataDir 數據目錄

啟動zk

bin/zkServer.sh start

使用客戶端連接

bin/zkCli.sh -server 127.0.0.1:2181

create /locks "" 
create /servers "" 
create /works ""

成功創建之后,命令窗口顯示

Created /servers

img

1. 不支持遞歸創建,必須先創建父節點 
2. 節點不能以 / 結尾,會直接報錯 
3. ZooKeeper 樹中的每一層級用斜杠(/)分隔開, 且只能用絕對路徑(如“get /work/task1”)的方式查詢 ZooKeeper 節點, 而不能使用相對路徑

數據模型是一種樹形結構 。

znode 節點類型與特性

zk中的數據節點也分為持久節點、臨時節點和順序節點 。

持久節點

持久節點一旦創建、該數據節點會一直存儲在zk服務器上、即使創建該節點的客戶端與服務端的會話關閉了、該節點也不會被刪除

臨時節點

如果將節點創建為臨時節點、那么該節點數據不會一只存儲在zk服務器上、當創建該臨時節點的客戶端繪畫因超時或發生異常而關閉時、該節點也相應的在zk上被刪除 。

有序節點

有序節點並不是一種單獨種類的節點、而是在吃酒節點和臨時節點的基礎上、增加了一個節點有序的性質 。

create -s /sequence-node- "" 
Created /sequence-node-0000000017 
第二次 
create -s /sequence-node- "" 
Created /sequence-node-0000000018
....... 
.......

上述幾種數據節點雖然類型不同、但zk中每個節點都維護有這些內容:一個二進制數組(用來存儲節點數據)、ACL訪問控制信息、子節點數據(因為臨時節點不允許有子節點、所以其子節點字段為null)、自身狀態信息字段stat 。

節點的狀態結構

get /servers stat /servers

返回的結果

cZxid = 0x4f0 
ctime = Thu May 07 21:53:04 CST 2020 
mZxid = 0x4f0 
mtime = Thu May 07 21:53:04 CST 2020 
pZxid = 0x4f0 
cversion = 0 
dataVersion = 0 
aclVersion = 0 
ephemeralOwner = 0x0 
dataLength = 0 
numChildren = 0
  • cZxid 創建這個節點的事務id
  • ctime 創建這個節點的時間
  • mZxid 修改這個節點的事務id
  • mtime 修改這個節點的時間
  • pZxid 表示該節點的子節點列表最后一次被修改時的事務id
  • cversion 這表示對此znode的子節點進行的更改次數
  • dataVersion 表示對該znode的數據所做的更改次數
  • aclVersion 表示對此znode的ACL進行更改的次數
  • ephemeralOwner 如果該節點是臨時節點、那么此字段記錄的是znode所有者的sessionId、如果不是則為0
  • dataLength znode 數據字段的長度 .
  • numChildre znode 子節點的數量

使用zookeeper實現鎖

針對超賣問題、使用zk實現鎖

悲觀鎖

認為對臨界區的競爭總是會出現、為了保證在操作數據時、該數據不被其他進程修改、數據一直會處於鎖定的狀態 。

我們假設一個具有 n 個進程的應用,同時訪問臨界區資源,我們通過進程創建 ZooKeeper 節點 /locks 的方式獲取鎖。

線程 a 通過成功創建 ZooKeeper 節點“/locks”的方式獲取鎖后繼續執行,如下圖所示:

img

線程 a 通過成功創建 ZooKeeper 節點“/locks”的方式獲取鎖后繼續執行,如下圖所示:

img

這樣就實現了一個簡單的悲觀鎖,不過這也有一個隱含的問題,就是當進程 a 因為異常中斷導致 /locks 節點始終存在,其他線程因為無法再次創建節點而無法獲取鎖,這就產生了一個死鎖問題。針對這種情況我們可以通過將節點設置為臨時節點的方式避免。並通過在服務器端添加監聽事件來通知其他進程重新獲取鎖。

樂觀鎖

進程對臨界區資源的競爭不會總是出現、所以相對悲觀鎖而已、假鎖方式沒那么激烈、不會全程鎖定資源、而是在數據進行提交更新的時候、對數據的沖突與否進行檢查、如果發現沖突了、則拒絕操作

樂觀鎖基本都是CAS、CAS有三個操作數、內存值V、舊的預期值A、修改的新值B、當預期值與內存值V 相等時、才將內存值V改成B

在zk中的version 屬性就是用來實現樂觀鎖機制中的檢驗的、zk中每個節點都有 dataVersion 這個字段、在調用更新操作的時候、加入有一個客戶端試圖進行更新操作、他會攜帶上次獲取到的version值進行更新、如果在這段時間內、zk服務器上該節點的數值恰好已經被其他客戶端更新了、那么 dataVersion一定發生變化、那么與當前客戶端的version 無法匹配、便無法更新

在 ZooKeeper 的底層實現中,當服務端處理 setDataRequest 請求時,首先會調用 checkAndIncVersion 方法進行數據版本校驗。ZooKeeper 會從 setDataRequest 請求中獲取當前請求的版本 version,同時通過 getRecordForPath 方法獲取服務器數據記錄 nodeRecord, 從中得到當前服務器上的版本信息 currentversion。如果 version 為 -1,表示該請求操作不使用樂觀鎖,可以忽略版本對比;如果 version 不是 -1,那么就對比 version 和 currentversion,如果相等,則進行更新操作,否則就會拋出 BadVersionException 異常中斷操作。

思考問題

為啥zk不采用相對路徑來查找結點?

這是因為 ZooKeeper 大多是應用場景是定位數據模型上的節點,並在相關節點上進行操作。像這種查找與給定值相等的記錄問題最適合用散列來解決。因此 ZooKeeper 在底層實現的時候,使用了一個 hashtable,即 hashtableConcurrentHashMap<String, DataNode> nodes ,用節點的完整路徑來作為 key 存儲節點數據。這樣就大大提高了 ZooKeeper 的性能。

新版本

zookeeper 3.5.x 中引入了 container 節點 和 ttl 節點(不穩定)

  1. container 節點用來存放子節點,如果container節點中的子節點為0 ,則container節點在未來會被服務器刪除。
  2. ttl 節點默認禁用,需要通過配置開啟, 如果ttl 節點沒有子節點,或者 ttl 節點在 指定的時間內沒有被修改則會被服務器刪除。

https://www.cnblogs.com/skyl/p/4854553.html

https://www.cnblogs.com/IcanFixIt/p/7846361.html

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=158#/detail/pc?id=3131


下次一定?


免責聲明!

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



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