分散式服務管理框架-Zookeeper客戶端zkCli.sh,zkCli.cmd使用詳解(轉載)
在學習zookeeper(下面簡稱zk)客戶端之前,有必要先了解一下zk的資料模型。zk維護著一個邏輯上的樹形層次結構,樹中的節點稱為znode,和Linux系統的檔案系統結構非常相似,如下圖所示:
這種資料結構有如下特點:
- 每個znode都有唯一路徑標識,最頂層的znode為/,比如p_2這個znode的路徑標識為/app1/p_2,znode只支援絕對路徑,不支援相對路徑,也不支援“.”和“..”
- znode可以有子節點,並且每個znode可以儲存資料。但zk是被設計用來協調管理服務的,因此znode裡儲存的都是一些小資料,而不是大容量的資料,資料容量一般在1M範圍內。
- znode的資料有版本號,可以用在併發訪問場景中,用樂觀鎖機制實現資料的一致性
- znode分為臨時節點和永久節點,zk的客戶端和伺服器通訊採用長連線的方式,每個客戶端和伺服器通過心跳來保持連線,這個連線狀態稱為session,如果znode是臨時節點,當session失效(即客戶端與伺服器斷開連線),znode會被伺服器自動刪除。
- znode的節點名稱可以自動編號,如果app1已經存在,再建立的話,將會自動命名為app2,這種節點稱為序列節點。
- znode可以被監控,包括這個節點中儲存的資料被修改、子節點列表變化(刪除或新增子節點)等,一旦變化,zk伺服器會通過所有監控該節點的客戶端,這是zk的核心特性,zk很多的功能都是基於這個特性實現的。
zkCli.sh指令碼是Zookeeper安裝包中自帶的一個客戶端,放在$ZK_HOME/bin
zkCli.sh客戶端連線到ZK伺服器的語法為:zkCli.sh -timeout 5000 -r -server ip:port
連線引數解釋:
- -timeout:表示客戶端向zk伺服器傳送心跳的時間間隔,單位為毫秒。因為zk客戶端與伺服器的連線狀態是通過心跳檢測來維護的,如果在指定的時間間隔內,zk客戶端沒有向伺服器傳送心跳包,伺服器則會斷開與該客戶端的連線。引數5000,表示zk客戶端向伺服器傳送心跳的間隔為5秒。
- -r:表示客戶端以只讀模式連線
- -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會遞迴刪除子節點,再刪除節點本身