1. 程式人生 > >分散式服務管理框架-Zookeeper客戶端zkCli.sh,zkCli.cmd使用詳解(轉載)

分散式服務管理框架-Zookeeper客戶端zkCli.sh,zkCli.cmd使用詳解(轉載)

在學習zookeeper(下面簡稱zk)客戶端之前,有必要先了解一下zk的資料模型。zk維護著一個邏輯上的樹形層次結構,樹中的節點稱為znode,和Linux系統的檔案系統結構非常相似,如下圖所示:
這裡寫圖片描述

這種資料結構有如下特點:

  1. 每個znode都有唯一路徑標識,最頂層的znode為/,比如p_2這個znode的路徑標識為/app1/p_2,znode只支援絕對路徑,不支援相對路徑,也不支援“.”和“..”
  2. znode可以有子節點,並且每個znode可以儲存資料。但zk是被設計用來協調管理服務的,因此znode裡儲存的都是一些小資料,而不是大容量的資料,資料容量一般在1M範圍內。
  3. znode的資料有版本號,可以用在併發訪問場景中,用樂觀鎖機制實現資料的一致性
  4. znode分為臨時節點和永久節點,zk的客戶端和伺服器通訊採用長連線的方式,每個客戶端和伺服器通過心跳來保持連線,這個連線狀態稱為session,如果znode是臨時節點,當session失效(即客戶端與伺服器斷開連線),znode會被伺服器自動刪除。
  5. znode的節點名稱可以自動編號,如果app1已經存在,再建立的話,將會自動命名為app2,這種節點稱為序列節點。
  6. znode可以被監控,包括這個節點中儲存的資料被修改、子節點列表變化(刪除或新增子節點)等,一旦變化,zk伺服器會通過所有監控該節點的客戶端,這是zk的核心特性,zk很多的功能都是基於這個特性實現的。

zkCli.sh指令碼是Zookeeper安裝包中自帶的一個客戶端,放在$ZK_HOME/bin

目錄下,本文ZK安裝在/opt/zookeeper-3.4.9。

zkCli.sh客戶端連線到ZK伺服器的語法為:zkCli.sh -timeout 5000 -r -server ip:port

連線引數解釋:

  1. -timeout:表示客戶端向zk伺服器傳送心跳的時間間隔,單位為毫秒。因為zk客戶端與伺服器的連線狀態是通過心跳檢測來維護的,如果在指定的時間間隔內,zk客戶端沒有向伺服器傳送心跳包,伺服器則會斷開與該客戶端的連線。引數5000,表示zk客戶端向伺服器傳送心跳的間隔為5秒。
  2. -r:表示客戶端以只讀模式連線
  3. -server:指定zk伺服器的IP與埠,zk預設的客戶端埠為2181
shell
> cd /usr/local/zookeeper/bin shell> ./zkCli.sh -timeout 5000 -server 127.0.0.1:2181

當然如果在Windows環境下,可以執行執行zkCli.cmd就能直接連線本地已啟動的zookeeper伺服器

這裡寫圖片描述

若出現上圖提示所示,表示已經成功連線到伺服器。

在客戶端互動命令列中,輸入h查詢可以使用的客戶端命令:

[zk: 127.0.0.1:2181(CONNECTED) 0] h
ZooKeeper -server host:port cmd args
    stat path [watch]
    set path data [version]
    ls path [watch]
    delquota [-n|-b] path
    ls2 path [watch]
    setAcl path acl
    setquota -n|-b val path
    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
    close
    connect host:port

這些命令的作用和關係型資料庫的SQL語句類似,zk的命令是對節點和資料進行增刪改查操作,而SQL則是對錶的資料增冊改查操作。下面詳細介紹所有命令的使用方法:

1、查詢子節點列表

語法:ls path
path:節點路徑

shell> ls /
[zookeeper] 

目前根節點下只有zookeeper一個節點,是zk預設建立的,用於儲存節點的一些狀態資訊,比如節點配額。

2、建立節點

語法:create path [-s] [-e] data acl
path:節點路徑
-s:指定該節點是一個序列節點,建立同名的節點時,會給節點自動加上編號
-e:指定該節點是一個臨時節點,預設是永久節點。臨時節點會在客戶端與伺服器斷開連線時,zk會將其建立的所有臨時節點全部刪除
data:儲存在節點中的資料
acl:設定子節點訪問許可權,預設所有人都可以對該節點進行讀寫操作

# 1> 在根目錄建立了一個`node_01`的節點,指定的資料為mydata
shell> create /node_01 mydata
Created /node_01
shell> ls /
[node_01, zookeeper]

# 2> 建立一個臨時節點(建立之後,可退出客戶端重新登入檢視該節點是否存在,來驗證臨時節點是否被刪除)
shell> create -e /node_02 "i is a ephemeral node"
Created /node_02

# 3> 建立一個序列臨時節點
shell> create -s -e /node_03 'i is a ephemeral sequence node'
Created /node_03

# 4> 建立一個永久序列節點(節點會自動加上編號)
shell> create -s /node_04 data
Created /node_040000000012
shell> create -s /node_04 data
Created /node_040000000013
shell> create -s /node_04 data
Created /node_040000000014

# 5> 建立一個帶許可權的節點,限制只能IP為192.168.1.101這臺機器訪問
## c:建立子節點許可權  
## d:刪除子節點許可權
## r:讀取子節點列表的許可權
## w:寫許可權,即修改子節點資料許可權
## a:管理子節點許可權
shell> create /node_04 mydata ip:192.168.1.101:cdrwa

注意:建立節點必須要為節點設定資料,否則會建立不成功。

3、獲取節點狀態

每個節點都包含描述該節點的一些狀態資訊,比如:節點資料、版本號等。
語法:stat path [watch]
path:節點全路徑
watch:監聽節點狀態變化

shell> stat /node_01 
cZxid = 0x2f
ctime = Sat Nov 12 15:54:05 CST 2016
mZxid = 0x2f
mtime = Sat Nov 12 15:54:05 CST 2016
pZxid = 0x2f
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0

在ZK中,ZK客戶端對伺服器每一個數據節點的寫操作,ZK會認為都是一次完整的事務操作,要麼成功,要麼失敗,保證了資料的原子性。而每次事務都會分配一個唯一的事務id,以標識這次事務操作的資料資訊。下面詳細理解一下節點狀態各個欄位的含義:
cZxid:建立節點的事務id
ctime:建立節點的時間
mZxid:修改節點的事務id
mtime:修改節點的時間
pZxid:子節點列表最後一次修改的事務id。刪除或新增子節點,不包含修改子節點的資料。
cversion:子節點的版本號,刪除或新增子節點,版本號會自增
dataVersion:節點資料版本號,資料寫入操作,版本號會遞增
aclVersion:節點ACL許可權版本,許可權寫入操作,版本號會遞增
ephemeralOwner:臨時節點建立時的事務id,如果節點是永久節點,則它的值為0
dataLength:節點資料長度(單位:byte),中文佔3個byte
numChildren:子節點數量

4、獲取節點資料

語法:get path [watch]
path:節點路徑
watch:監聽節點資料變化。如果其它客戶端修改了該節點的資料,則會通知監聽了該節點的所有客戶端

shell> get /node_01
mydata
cZxid = 0x2f
ctime = Sat Nov 12 15:54:05 CST 2016
mZxid = 0x2f
mtime = Sat Nov 12 15:54:05 CST 2016
pZxid = 0x2f
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0

/node_01的節點資料為mydata,即節點狀態資訊的第一行

5、設定節點資料

語法:set path data [version]
path:節點路徑
data:節點資料
version:資料版本號(節點狀態dataVersion的值)

shell> set /node_01 hello
cZxid = 0x2f
ctime = Sat Nov 12 15:54:05 CST 2016
mZxid = 0x30
mtime = Sat Nov 12 15:55:01 CST 2016
pZxid = 0x2f
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

此時可以看到dataVersion狀態的值變成了1。預設不加版本號則會覆蓋節點之前設定的資料,如果加上版本號,版本號必須和伺服器上的版本號一致,否則會報錯,如下所示:

shell> set /node_01 updatedata 2
version No is not valid : /node_01

這種機制和資料庫中的樂觀索機制非常相似:

想象一種場景,在獲取某個節點的資料之後,利用資料處理完業務邏輯,不加版本號,直接修改節點的資料。但在獲取和修改節點資料的這一小段時間窗內,很有可能有其它客戶端也修改了該節點的資料,而節點資料變化會使節點狀態的dataVersion值遞增。如果我們獲取節點資料處理完成自己的業務邏輯,然後不加上版本號直接修改節點資料時,則會覆蓋掉其它客戶端修改的最新資料,從而導致資料不一致的情況。所以要保證資料的一致性時,修改節點資料時,應該加上最新的版本號。而在這個場景中,我們在處理完業務邏輯,再修改節點資料時帶上節點的版本號,這時若有其它節點修改了資料,修改則會失敗。此時我們應該馬上再獲取一次節點的最新版本號,再做修改。

6、查詢子節點列表及狀態資訊

語法:ls2 path [watch]
path:節點路徑
watch:是否監聽子節點列表變化通知

# 先在/node_1節點下建立幾個子節點
shell> create /node_01/node_01_01 abc
Created /node_01/node_01_01
shell> create /node_01/node_01_02 def
Created /node_01/node_01_02
shell> ls2 /node_01
[node_01_01, node_01_02]
cZxid = 0x2f
ctime = Sat Nov 12 15:54:05 CST 2016
mZxid = 0x30
mtime = Sat Nov 12 15:55:01 CST 2016
pZxid = 0x39
cversion = 2
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 2

第一行是/node_01的子節點列表,後面的資訊是/node_01節點的狀態資訊。和ls命令不一樣的是,ls2不僅能查詢節點的子節點列表,同時也能查詢到節點的狀態資訊。

7、刪除節點

語法:delete path [version]
path:節點路徑
version:節點版本號(節點狀態cversion的值),可選。如果傳遞了版本號,則必須保證和伺服器的版本號一致,否則會報錯:version No is not valid : 節點路徑

shell> delete /path/node_01/node_01_01

注意:delete只能刪除沒有子節點的節點,否則會報錯,如下所示:

shell> delete /node_01
Node not empty: /node_01

8、刪除節點(包括子節點)

語法:rmr path
path:節點路徑

shell> rmr /node_01

rmr會遞迴刪除子節點,再刪除節點本身