.原文链接:http://blog.csdn.net/xyang81/article/details/53053642

在学习zookeeper(下面简称zk)客户端之前,有必要先了解一下zk的数据模型。zk维护着一个逻辑上的树形层次结构,树中的节点称为znode,和Linux系统的文件系统结构非常相似,如下图所示:
Zookeeper数据结构
这种数据结构有如下特点:
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

zkCli.sh连接服务器成功
若出现上图提示所示,表示已经成功连接到服务器。

在客户端交互命令行中,输入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会递归删除子节点,再删除节点本身

9、设置节点配额

节点可以存储数据,也可以创建子节点,但是如果不做控制,节点数据可以无限大,子节点数量也可以创建无数个,所以在有些场景下需要对节点的数据和子节点的数量需要做一些限制,zk为我们提供了setauota命令实现对子节点的限制功能。但是,zk并不是真正在的物理上对节点做了限制,而是如果超过了节点限制,会在zk的日志文件中记录配额超限的警告信息。

语法:setquota -n|-b val path
-n:限制子节点的数量
-b:限制节点的数据长度
val:根据-n和-b参数不同,val值的意义也不一样。如果是-n参数,val表示限制子节点的数量。如果是-b参数,val表示限制节点的数据长度
path:节点路径

shell> setquota -n 2 /node_01
Comment: the parts are option -n val 2 path /node_01

上面我对/node_01限制它最多只能有2个子节点,下面我在/node_01节点下创建3个节点看看效果:

shell> create /node_01/node_01_01 abc
Created /node_01/node_01_01
shell> create /node_01/node_01_02 abc
Created /node_01/node_01_02
shell> create /node_01/node_01_03 abc
Created /node_01/node_01_03

你可能会觉得奇怪,我明明限制了/node_01节点最多只能有2个节点,在创建第3个节点的时候并没有报错,也创建成功了,为什么限制没有起作用呢? 在上面我也提到了,zk并没有在物理上限制节点的数量和数据的长度,当节点超过了限制,zk只会在后台记录节点限制的日志信息。下面我们看下zk日志文件中输出的节点配额限制警告信息:

shell> tail /var/log/zookeeper/zookeeper.log
...
2016-11-12 17:29:20,196 [myid:] - WARN  [SyncThread:0:DataTree@301] - Quota exceeded: /node_01 count=3 limit=2

日志中输出的警告信息count=3,表示/node_01节点当前有3个子节点。limit=2,表示/node_01节点最多只能有2个节点。

zk默认会在启动服务的目录生成一个zookeeper.out日志文件,即执行zkServer.sh start命令的目录。我修改了zk默认日志文件目录为/var/log/zookeeper,你也可以参考《分布式服务管理框架-Zookeeper日志配置》自行修改。

10、查询节点配额

语法:listquota path
path:节点路径

shell> listquota /node_01
absolute path is /zookeeper/quota/node_01/zookeeper_limits
Output quota for /node_01 count=2,bytes=-1
Output stat for /node_01 count=4,bytes=12

Output quota:表示节点的配额信息,限制该节点最多有2个子节点,节点数据为-1,表示不限制
Output stat:表示当前节点的状态信息,该节点有4个子节点,节点数据长度为12

11、删除节点配额

语法:delquota [-n|-b] path
-n:删除子节点数量配额限制
-b:删除节点数据长度配额限制
path:节点路径

# 删除/node_01节点子节点数量限制
shell> delquota -n /node_01
shell> listquota /node_01
absolute path is /zookeeper/quota/node_01/zookeeper_limits
# count=-1表示没有子节点数量限制
Output quota for /node_01 count=-1,bytes=-1
Output stat for /node_01 count=4,bytes=12

12、获取节点ACL

ACL是zk对节点权限控制的一种策略
语法:getAcl path
path:节点路径

shell> getAcl /node_01
'world,'anyone
: cdrwa

创建节点时如果没有设置acl权限,默认为所有用户都可以对该节点进行读写操作。

13、设置节点ACL

语法:setAcl path acl
path:节点路径
acl:ACL权限模式

shell> setAcl /node_01 ip:192.168.1.101:rcdwa
cZxid = 0x65
ctime = Sat Nov 12 17:29:06 CST 2016
mZxid = 0x65
mtime = Sat Nov 12 17:29:06 CST 2016
pZxid = 0x68
cversion = 3
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 3

设置/node_01节点,只允许IP为192.168.1.101的客户端访读写/node_01的数据,但不允许创建、查询、删除子节点和不允许设置节点权限。节点ACL详细介绍请参考《分布式服务管理框架-Zookeeper节点ACL》

14、给当前客户端添加授权信息

语法:addauth scheme auth
scheme:授权方式
auth:权限
addauth一般用于digest授权方式添加授权信息。digest是用户名和密码授权,语法:username:BASE64(SHA1(password))

shell> addauth digest yangxin:123456

给当前客户端添加授权信息,授权模式为digest(用户名/密码授权),用户名为yangxin,密码为123456

15、查看历史命令

可查询之前执行过的命令,会列出前最后10条命令,和linux中的history命令功能一样

shell> history
11 - setAcl /node_04 ip:192.168.1.101:cra
12 - setAcl /node_04 ip:192.168.1.101:craw
13 - create /node_04/node_04_01 aaa
14 - delete /node_04/node_04_01
15 - get /node_04/node_04_01
16 - getAcl /node_04/node_04_01
17 - getAcl /node_04
18 - h
19 - addauth ip rwcda
20 - getAcl /node_04
21 - history

16、执行历史命令

语法:redo cmdno
cmdno:历史命令编号

shell>redo 17
'ip,'192.168.1.101
: crwa

和linux中!命令编号命令的作用一样

17、与leader同步数据

语法:sync path
path:节点路径

在对某个znode进行读操作时,应该先执行sync方法,使得读操作的连接所连的zk实例能与leader进行同步,从而保证能读到最新的数据。
注意:sync调用是异步的,无需等待调用的返回,zk服务器会保证所有后续的操作会在sync操作完成之后才执行,哪怕这些操作是在执行sync之前被提交的。

shell> sync /node_01

18、打开或关闭监听日志

在获取节点数据、子节点列表等操作时,都可以添加watch参数监听节点的变化,从而节点数据更改、子节点列表变更时收到通知,并输出到控制台。默认是打开,可以设置参数将其关闭。
语法:printwatches on|off
on:打开
off:关闭

shell> printwatches off

19、关闭连接

close命令会关闭当前客户端连接

20、连接到zk服务器

语法:connect host:port
host:port:IP和zk客户端端口

shell>connect 192.168.1.102:2181

21、退出zkCli.sh终端

quit

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐