ZooKeeper CLI(客戶端)
ZooKeeper命令行界面(CLI)用於與ZooKeeper服務端進行交互,以進行開發。它有助於調試和解決不同的選項。
要執行ZooKeeper CLI操作,首先打開ZooKeeper服務器。
進入ZooKeeper的bin目錄執行以下命令
./zkServer.sh start
啓動成功
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper-3.4.9/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
然後打開ZooKeeper客戶端
./zkCli.sh
啓動成功
Connecting to localhost:2181
2019-08-24 17:21:13,419 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.9-1757313, built on 08/23/2016 06:50 GMT
2019-08-24 17:21:13,422 [myid:] - INFO [main:Environment@100] - Client environment:host.name=bogon
2019-08-24 17:21:13,422 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.8.0_181
2019-08-24 17:21:13,424 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
2019-08-24 17:21:13,424 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.181-7.b13.el7.x86_64/jre
2019-08-24 17:21:13,424 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/opt/zookeeper-3.4.9/bin/../build/classes:/opt/zookeeper-3.4.9/bin/../build/lib/*.jar:/opt/zookeeper-3.4.9/bin/../lib/slf4j-log4j12-1.6.1.jar:/opt/zookeeper-3.4.9/bin/../lib/slf4j-api-1.6.1.jar:/opt/zookeeper-3.4.9/bin/../lib/netty-3.10.5.Final.jar:/opt/zookeeper-3.4.9/bin/../lib/log4j-1.2.16.jar:/opt/zookeeper-3.4.9/bin/../lib/jline-0.9.94.jar:/opt/zookeeper-3.4.9/bin/../zookeeper-3.4.9.jar:/opt/zookeeper-3.4.9/bin/../src/java/lib/*.jar:/opt/zookeeper-3.4.9/bin/../conf:
2019-08-24 17:21:13,424 [myid:] - INFO [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2019-08-24 17:21:13,424 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=<NA>
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=amd64
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:os.version=3.10.0-957.el7.x86_64
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root
2019-08-24 17:21:13,425 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/opt/zookeeper-3.4.9/bin
2019-08-24 17:21:13,426 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@7aec35a
2019-08-24 17:21:13,460 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server localhost/0:0:0:0:0:0:0:1:2181. Will not attempt to authenticate using SASL (unknown error)
Welcome to ZooKeeper!
JLine support is enabled
2019-08-24 17:21:13,607 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socket connection established to localhost/0:0:0:0:0:0:0:1:2181, initiating session
2019-08-24 17:21:13,639 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/0:0:0:0:0:0:0:1:2181, sessionid = 0x16cc029862a0005, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
一旦ZooKeeper客戶端啓動成功,我們就可以和ZooKeeper服務端進行交互。
輸入help
命令(其實輸入任何 zkCli 不能識別的命令,都會列出所有的命令),查看可用的命令:
help
結果:
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
現在讓我們用一個例子逐個瞭解上面的命令
創建節點 create
語法
create [-s] [-e] path data acl
注意:如果該節點不需要存儲任何數據則用''
字符串表示,不可忽略,否則會報錯。
-s
創建有序節點
順序節點可以是持久的或臨時的。當一個新的節點被創建爲一個順序節點時,ZooKeeper通過將10位的序列號附加到原始名稱來設置節點的路徑。
例如,如果將具有路徑 /myapp 的節點創建爲順序節點,則ZooKeeper會將路徑更改爲/myapp0000000001 ,並將下一個序列號設置爲0000000002。如果兩個順序節點是同時創建的,那麼ZooKeeper不會對每個節點使用相同的數字。順序節點在鎖定和同步中起重要作用。
這個序號的計數器是由這些排序節點的父節點來維護的。
-e
創建臨時節點
客戶端活躍時,臨時節點就是有效的。當客戶端與ZooKeeper集合斷開連接時,臨時節點會自動刪除。因此,只有臨時節點不允許有子節點。如果臨時節點被刪除,則下一個合適的節點將填充其位置。臨時節點在leader選舉中起着重要作用。
acl
我們單獨在ZooKeeper之ACL做介紹。
使用方法:
創建普通節點
create /mynode monkey
結果:
Created /mynode
創建子節點
在/mynode
節點下添加一個名爲/subnode
的子節點
create /mynode/subnode ''
結果:
Created /mynode/subnode
如果父節點不存在,則會先創建父節點後再創建子節點。
注意:臨時節點不能擁有子節點。
創建有序節點
create -s /mynode ''
create -s /mynode ''
結果:
Created /mynode0000000003
Created /mynode0000000004
創建臨時節點
create -e /temp ''
結果:
Created /temp
關閉當前會話,然後重新打開它,發現/tmep
節點已經被刪除了。
創建臨時有序節點
create -s -e /mynode ''
結果:
Created /mynode0000000006
關閉當前會話,然後重新打開它,發現/mynode0000000006
節點已經被刪除了。
列出znode的子節點 ls or ls2
語法
ls path [watch]
ls
命令類似於Linux中的dir
ls2 path [watch]
ls2
命令來查看當前節點的所有子節點並能看到更新次數等數據,與ls
不同的是它可以當前節點的stat(狀態)。
watch
添加一個監視器
[watch]
添加一個watch
(監視器)如果該節點發生變化,watch
可以使客戶端得到通知。watch 只能被觸發一次。如果要一直獲得znode的創建和刪除的通知,那麼就需要不斷的在znode上開啓觀察模式。
如果在該 path 下創建或刪除子節點,會產生 NodeChildrenChanged
事件;如果刪除自身節點則會產生 NodeDeleted
事件。
使用方法:
ls
列出根節點下的所有子節點
ls /
結果:
[mynode0000000006, mynode, zookeeper, mynode0000000003]
ls2
列出根節點
ls2 /
結果:
[mynode0000000006, mynode, zookeeper, mynode0000000003]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 HKT 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 HKT 1970
pZxid = 0x2c
cversion = 10
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 4
列出子節點
ls /mynode
結果:
[subnode]
使用watch
我們在根節點創建一個名爲a
的watch
ls / a
然後再根節點下添加子節點
create /mynode2 hello
就會觸發該watch
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/
Created /mynode2
注意:在其他節點下創建子節點,不會觸發該watch
。
從上面的操作可以看到,在根節點添加了 /mynode2
節點之後,觸發了 watch
,WatchedEvent
的類型是 NodeChildrenChanged
。
獲取節點信息 get
語法
get path [watch]
watch
添加一個監視器
[watch]
添加一個watch
(監視器)如果該節點發生變化,watch
可以使客戶端得到通知。watch 只能被觸發一次。如果要一直獲得znode的創建和刪除的通知,那麼就需要不斷的在znode上開啓觀察模式。
如果節點內容發生改變,會產生NodeDataChanged
事件;如果刪除節點,會產生NodeDeleted
事件。
獲取/mynode
數據
get /mynode
結果
22
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x3e
mtime = Sun Aug 25 14:27:54 HKT 2019
pZxid = 0x3d
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0
每一個對znode樹的更新操作,都會被賦予一個全局唯一的ID,我們稱之爲zxid
(Zookeeper Transaction ID)。更新操作的ID按照發生的時間順序升序排序。
Znode(節點)的stat結構中的字段顯示如下,各自的含義如下:
- cZxid - 創建該
znode
的zxid
。 - ctime - 創建該
znode
的時間。 - mZxid - 這是最後修改
znode
更改的事務ID。 - mtime - 最後一次修改該
znode
的時間。 - pZxid - 這是用於添加或刪除子節點的
znode
更改的事務ID。 - cversion - 該
znode
的子節點的版本。 - dataVersion -
znode
內容的版本,每次修改內容,版本都會增加。 - aclVersion -
znode
的ACL
的版本。 - ephemeralOwner - 如果
znode
是ephemeral(臨時)節點,會列出該znode
所在客戶端的session id
;如果不是臨時節點,該值爲0
。 - dataLength - 該
znode
存儲的數據長度。 - numChildren - 該
znode
的子節點的個數。
使用watch
我們在/mynode
節點創建一個名爲a
的watch
get /mynode a
然後更改/mynode
節點的數據
set /mynode 111
就會觸發watch
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/mynode
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x40
mtime = Sun Aug 25 17:08:53 HKT 2019
pZxid = 0x3f
cversion = 1
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
從上面的操作可以看到,在修改/mynode
的數據後,觸發了 watch
,WatchedEvent
的類型是 NodeDataChanged
。
檢查狀態 stat
語法
stat path [watch]
watch
添加一個監視器
[watch]
添加一個watch
(監視器)如果該節點發生變化,watch
可以使客戶端得到通知。watch 只能被觸發一次。如果要一直獲得znode的創建和刪除的通知,那麼就需要不斷的在znode上開啓觀察模式。
如果節點內容發生改變,會產生NodeDataChanged
事件;如果刪除節點,會產生NodeDeleted
事件。
使用方法:
查看/mynode
狀態
stat /mynode
結果:
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x40
mtime = Sun Aug 25 17:08:53 HKT 2019
pZxid = 0x3f
cversion = 1
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
與get
的區別是,不會列出節點的數據。
使用watch
我們在/mynode
節點創建一個名爲a
的watch
stat /mynode a
然後更改/mynode
節點的數據
set /mynode 222
就會觸發watch
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/mynode
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x41
mtime = Sun Aug 25 22:22:24 HKT 2019
pZxid = 0x3f
cversion = 1
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
從上面的操作可以看到,在修改/mynode
的數據後,觸發了 watch
,WatchedEvent
的類型是 NodeDataChanged
。
設置數據 set
語法
set path data [version]
修改已經存在的節點的數據。
version
指定版本號設置數據
[version]
參數用於指定節點的數據版本,表名本次更新操作是針對指定的數據版本進行更新的。
如果指定znode版本號,需要與當前的版本號匹配。如果版本號不匹配,操作將會失敗。失敗的原因可能是在我們提交之前,該znode已經被修改過了,版本號發生了增量變化。如果不指定版本號,就是直接操作最新版本的 znode。
使用方法
修改/mynode
的數據爲sayhello
set /mynode sayhello
結果:
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x47
mtime = Sun Aug 25 23:18:27 HKT 2019
pZxid = 0x3f
cversion = 1
dataVersion = 5
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 1
我們通過get
命令來查看/mynode
sayhello
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x47
mtime = Sun Aug 25 23:18:27 HKT 2019
pZxid = 0x3f
cversion = 1
dataVersion = 5
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 1
可以看到sayhello
已經被設置進去了。
我們來看看帶version
參數的set
通過stat
命令我們可以看到mynode
的dataVersion
爲11
修改/mynode
的數據爲sayhi
,指定版本參數爲11
set /mynode sayhi 11
結果:
cZxid = 0x3d
ctime = Sun Aug 25 14:27:31 HKT 2019
mZxid = 0x5d
mtime = Mon Aug 26 11:19:56 HKT 2019
pZxid = 0x3f
cversion = 1
dataVersion = 12
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 1
可以看到,在修改節點值之後,mZxid
、mtime
、dataVersion
都發生了變化。
注意:如果version
參數和/mynode
節點的dataVersion
所對應不上則會提示version No is not valid :/mynode
(版本號無效:/mynode),並且修改數據失敗。
指定版本更新的意義何在?
通俗來講就是CAS
(樂觀鎖),每次更新攜帶上次獲取到的vesion
值進行更新。而如果在這段時間內,ZooKeeper服務器上該節點的數值恰好已經被其它客戶端更新了,那麼其節點的version
值也一定會發生變化,一旦節點的version
值發生了變化。我們的本次攜帶的vesion
值就無法和服務端節點的vesion
值匹配,於是便無法成功更新。 – 因此可以有效地避免一些分佈式更新的併發問題
刪除節點 rmr
語法
rmr path
使用方法:
刪除/mynode
節點
rmr /mynode
使rmr
命令刪除,不會返回任何內容。如果有子節點的時候,連帶子節點也一起刪除。
我們通過ls
命令來查看/mynode
節點是否被刪除了。
ls /
結果:
[zookeeper, mynode0000000003]
可以看到/mynode
節點已經被刪除了。
刪除節點 delete
語法
delete path [version]
version
指定版本號刪除節點
[version]
參數用於指定節點的數據版本,表名本次更新操作是針對指定的數據版本進行更新的。如果指定znode版本號,需要與當前的版本號匹配。如果版本號不匹配,操作將會失敗。失敗的原因可能是在我們提交之前,該znode已經被修改過了,版本號發生了增量變化。如果不指定版本號,就是直接操作最新版本的 znode。
使用方法:
我們先使用create
創建一個名爲/mynode
節點
create /mynode ''
結果:
Created /mynode
接着我們來使用delete
命令刪除/mynode
節點。
delete /mynode
使delete
命令刪除,不會返回任何內容。如果有子節點的時候,將不能刪除。
我們通過ls
命令來查看/mynode
節點是否被刪除了。
ls /
結果:
[zookeeper, mynode0000000003]
可以看到/mynode
節點已經被刪除了。
我們來看看帶version
參數的delete
我們先使用create
創建一個名爲/mynode
節點
create /mynode ''
結果:
Created /mynode
通過stat
命令我們可以看到mynode
的dataVersion
爲0
刪除/mynode
,指定版本參數爲0
delete /mynode 0
我們通過ls
命令來查看/mynode
節點是否被刪除了。
ls /
結果:
[zookeeper, mynode0000000003]
可以看到/mynode
節點已經被刪除了。
注意:如果version
參數和/mynode
節點的dataVersion
所對應不上則會提示version No is not valid :/mynode
(版本號無效:/mynode),並且刪除失敗。
delete
和rmr
的區別
delete
只能刪除葉節點,也就是說帶有子節點的節點將刪除失敗,相反rmr
可以刪除帶有子節點的節點。delete
能帶version
進行刪除,相反rmr
不支持
其他指令
歷史記錄 history
語法
history
使用方法:
列出最近的10條歷史記錄。
history
結果:
14 - rmr /mynode
15 - ls /
16 - create /mynode ''
17 - delete /mynode
18 - ls /
19 - create /mynode ''
20 - stat /mynode
21 - delete /mynode 1
22 - delete /mynode 0
23 - help
24 - history
重複之前的命令 redo
語法
redo cmdno
使用方法:
根據 cmdno 重複之前的命令,cmdno 就是方括號裏面最後的數字,每次執行命令都會自增
[zk: localhost:2181(CONNECTED) 28] create /mynode ''
Created /mynode
[zk: localhost:2181(CONNECTED) 29] rmr /mynode
[zk: localhost:2181(CONNECTED) 30] redo 28
Created /mynode
是否輸出 watch 事件 printwatches on | off
語法
printwatches on|off
on
代表會輸出watch
事件,off
代表不會輸出watch
事件
使用方法:
查看當前printwatches
的值
printwatches
結果:
printwatches is on
我們在根節點創建一個名爲a
的watch
ls / a
並刪除掉根節點中的其中一個子節點,觸發watch
rmr /mynode
結果:
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/
輸出了watch
事件
我們將printwatches
的值更改爲off
printwatches off
我們繼續在根節點創建一個名爲a
的watch
ls / a
並在根節點中創建一個子節點,觸發watch
create /mynode ''
結果:
Created /mynode
並沒有輸出watch
事件.
關閉連接 close
語法
close
使用方法:
關閉連接(會話)
close
結果:
2019-08-26 18:07:57,745 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x16cc029862a000d closed
[zk: localhost:2181(CLOSED) 39] 2019-08-26 18:07:57,748 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@519] - EventThread shut down for session: 0x16cc029862a000d
再次對節點操作時
ls /
結果:
Not connected
打開連接 connect
語法
connect host:port
指定 host:port 可以連接遠程的 zk 服務。缺省的時候,會連接本地的 2181 端口。
使用方法:
連接本地的ZooKeeper服務端
connect localhost:2181
結果:
2019-08-26 18:15:32,037 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@73a8dfcc
[zk: localhost:2181(CONNECTING) 4] 2019-08-26 18:15:32,041 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
2019-08-26 18:15:32,043 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socket connection established to localhost/127.0.0.1:2181, initiating session
2019-08-26 18:15:32,055 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x16cc029862a000f, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
再次對節點操作時
ls /
結果:
[mynode, zookeeper, mynode0000000003]
連接成功!!!
如果是連接本地ZooKeeper服務端並端口號是2181
。則可以省略host:port
參數。
退出客戶端 quit
語法
quit
直接退出當前的 zkCli 命令行。
使用方法:
退出客戶端
[zk: localhost:2181(CONNECTED) 6] quit
結果:
[root@bogon bin]#
強制同步 sync
語法
sync path
sync
方法會強制客戶端所連接的服務器狀態與leader的狀態同步,這樣在讀取節點的值就是最新的值了。
使用方法:
同步/mynode
節點
sync /mynode
結果:
Sync returned 0
由於我這邊是單機架構所以returned
爲 0