本文是基于 zookeeper 3.6.1
编写的
节点操作
新增节点
create [-s] [-e] path [data] # 其中-s表示有序节点,-e表示临时节点
通过该条命令,可以简单将节点划分为四种:
- 持久+有序节点
- 持久+无序节点
- 临时+有序节点
- 临时+无序节点
持久节点
默认create
就是创建的持久化节点:
如果要创建持久化+有序节点,那么加上create /a "111"
-s
即可:[zk: localhost:2181(CONNECTED) 2] create -s /a "aaaa"
Created /a0000000003
作用:可以用持久化有序节点,为分布式系统提供唯一的ID。
临时节点
临时节点的生命周期取决于 **session
** ,如果session结束了,那么临时节点的一生就结束了。
如果要创建临时节点,需要加上参数 -e
:
[zk: localhost:2181(CONNECTED) 5] create -e /ea "eaaaaaaaaaa"
Created /ea
如果要创建临时+有序节点,需要额外加上参数 -s
:
[zk: localhost:2181(CONNECTED) 6] create -e -s /eb "ebbbbbbbbbbbbbbb"
Created /eb0000000005
临时有序节点在session结束以后虽然会被销毁,但是它的序号并不会跟着消失,而是继续往后递增。
更新节点
更新命令为:
set [-s] [-v <version>] <PATH> <DATA>
,指定节点 - ,要修改的数据
- [-v version],类似mysql的乐观锁的版本号;如果版本对应上了,那么久执行更新,如果没对上就拒绝更新。优点类似于CAS操作。
- [-s],更新完后输出更新后的状态
更新前:
[zk: localhost:2181(CONNECTED) 2] get -s /zoo01
123
cZxid = 0x9
ctime = Fri Jun 26 03:04:26 EDT 2020
mZxid = 0x9
mtime = Fri Jun 26 03:04:26 EDT 2020
pZxid = 0x9
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
更新后:
[zk: localhost:2181(CONNECTED) 3] set /zoo01 "1111111111111"
[zk: localhost:2181(CONNECTED) 4] get -s /zoo01
1111111111111
cZxid = 0x9
ctime = Fri Jun 26 03:04:26 EDT 2020
mZxid = 0x18
mtime = Fri Jun 26 04:34:26 EDT 2020
pZxid = 0x9
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 0
如果加上版本号限制,那么只有给定的 version
匹配上了该节点的 dataVersion
,才允许更新,接着上面
[zk: localhost:2181(CONNECTED) 19] set /zoo01 "9999" -v 9
version No is not valid : /zoo01
删除节点
命令格式:
delete [-v <version>] <PATH>
删除 /zoo01
节点:
[zk: localhost:2181(CONNECTED) 21] delete -v 9 /zoo01
version No is not valid : /zoo01
[zk: localhost:2181(CONNECTED) 22] delete -v 6 /zoo01
[zk: localhost:2181(CONNECTED) 23]
注意,该命令删除的节点一定不能有子节点(即使子节点是null)!!!
[zk: localhost:2181(CONNECTED) 23] create /zoo01
Created /zoo01
[zk: localhost:2181(CONNECTED) 24] create /zoo01/node01
Created /zoo01/node01
[zk: localhost:2181(CONNECTED) 25] delete /zoo01
Node not empty: /zoo01
旧版本:如果想要删除有子节点的节点,需要使用命令 rmr <PATH>
新版本:使用命令 deleteall <PATH>
,删除某个路径及其子节点, deleteall <PATH>
的格式如下所示:
deleteall path [-b batch size]
- [-b batch size],目前没弄懂干嘛用的;个人猜测是用来提高吞吐量的
查看节点
查看命令格式如下所示:
get [-s] [-w] path
[-s]
,获取数据的同时打印该节点的状态[-w]
,获取数据的同时,给这个节点加上一个WATCH
。使用该参数的时候,需要启用printwatches
。直接输入printwatches on
即可[zk: localhost:2181(CONNECTED) 30] printwatches printwatches is on
状态属性 | 说明 |
---|---|
cZxid | 该节点创建时的事务ID |
ctime | 该节点创建时的时间 |
mZxid | 该节点最后一次修改的事务ID |
mtime | 该节点最近一次的更新时间 |
pZxid | 该节点内最后一次新增、删除子节点(直接子节点,子节点的子节点不算)时的事务ID |
cversion | 子节点(直接子节点,子节点的子节点不算)的新增、删除次数。子节点的内容变更不算 |
dataVersion | 该节点的数据更改次数 |
aclVersion | 结点的ACL(权限)更改次数——类似linux 的权限列表,维护的是当前结点的权限列表被修改的次数 |
ephemeralOwner | 如果结点是临时结点,则表示创建该结点的会话的SessionID ;如果是持久结点,该属性值为0 |
dataLength | 该节点的数据长度 |
numChildren | 该节点的子节点个数 |
查看节点
使用 get [-w] [-s] PATH
,其中:
[-w]
,表示监听[-s]
,表示顺带着输出节点状态信息 ```bash [zk: localhost:2181(CONNECTED) 77] get -w /zoo01 2 [zk: localhost:2181(CONNECTED) 78] set /zoo01 “11” WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/zoo01
<a name="2srkj"></a>
### 查看节点状态
使用 `stat [-w] PATH` 查看节点状态,相当于使用 `get -s PATH` 。其中的 `[-w]` 表示监听该节点的状态修改情况。注意是 `type:NodeDataChanged`
```bash
[zk: localhost:2181(CONNECTED) 68] stat -w /zoo01
cZxid = 0x26
ctime = Fri Jun 26 05:13:28 EDT 2020
mZxid = 0x26
mtime = Fri Jun 26 05:13:28 EDT 2020
pZxid = 0x2c
cversion = 3
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
[zk: localhost:2181(CONNECTED) 70] set /zoo01 "1111"
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/zoo01
查看节点列表
旧版本:使用 ls PATH
,查看某个路径下的所有子节点
新版本:使用 ls [-s] [-w] [-R] PATH
,查看某个路径下的所有子节点,其中:
-s
,表示顺带着显示子节点元数据信息-w
,监视子节点的增、删信息,注意!是增、删信息,修改数据的内容不管(注意type:NodeChildrenChanged
) ```bash [zk: localhost:2181(CONNECTED) 72] ls -w /zoo01 [a] [zk: localhost:2181(CONNECTED) 73] set /zoo01/a “222” # 给ls加上watch,修改子节点的内容不触发watch [zk: localhost:2181(CONNECTED) 74] create /zoo01/b “33” # 只有创建/删除节点才会触发watch WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zoo01
- `-R` ,递归显示子节点的子节点(不能和 `-s` 一起使用,一起使用的话仅 `-R` 生效)
```bash
[zk: localhost:2181(CONNECTED) 65] ls -s /zoo01
[a]
cZxid = 0x26
ctime = Fri Jun 26 05:13:28 EDT 2020
mZxid = 0x26
mtime = Fri Jun 26 05:13:28 EDT 2020
pZxid = 0x2c
cversion = 3
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
[zk: localhost:2181(CONNECTED) 64] ls -s -R /zoo01
/zoo01
/zoo01/a
/zoo01/a/b
ACL权限控制
zookeeper里面权限分为三个部分:
- 授权模式(scheme)
- world,只有一个用户,就是anyone(root?)
- ip,对客户端使用IP进行认证
- auth,使用已添加认证用户进行认证。提供用户名密码时,密码是明文的
- digest,用户名+密码认证。提供的是加密的
- 授权对象(id)
- world的授权对象是anyone用户
- ip的授权对象是某个具体的ip地址
- auth和digest是具体要认证的某个用户
- 权限(permission)
- create(
c
),在当前节点下创建子节点的权限 - delete(
d
),在当前节点删除子节点(仅直接节点,子节点的子节点无效)的权限 - read(
r
),读取节点数量及显示子节点列表的权限 - write(
w
),设置节点数据的权限 - admin(
a
),可以设置节点访问控制列表权限(就是管理权限的权限)
- create(
命令 | 使用示例 | 描述 |
---|---|---|
getAcl [-s] PATH |
getAcl /zoo01 | 查看某个节点的ACL权限 |
setAcl [-s] [-v <version>] PATH SCHEME:ID:ACL |
setAcl /zoo world:anyone:craw | 设置ACL权限 |
addauth | addauth | 添加认证用户 |
world模式实战
移除 /zoo
节点的的create权限,那么就不能在该节点下创建直接子节点
[zk: localhost:2181(CONNECTED) 88] getAcl /zoo/a
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 89] setAcl /zoo world:anyone:drwa
[zk: localhost:2181(CONNECTED) 90] create /zoo/c
Authentication is not valid : /zoo/c
[zk: localhost:2181(CONNECTED) 91] create /zoo/a/aa
Created /zoo/a/aa
[zk: localhost:2181(CONNECTED) 92]
注意, stat
命令不受任何权限影响,都能执行(以前的版本 getAcl
也不受权限的影响,新版本会受 read
权限的影响了)
ip模式
授权对象一旦指向了别人,自己就没的办法了。
本地localhost,给 192.168.136.134
设置了ip模式的 crw
权限:
[zk: localhost:2181(CONNECTED) 2] getAcl /keeper
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 3] setAcl /keeper ip:192.168.136.134:crw
[zk: localhost:2181(CONNECTED) 4] getAcl /keeper
Authentication is not valid : /keeper
[zk: localhost:2181(CONNECTED) 5]
192.168.136.134的主机:
[zk: 192.168.136.128(CONNECTED) 1] getAcl /keeper
'ip,'192.168.136.134
: crw
[zk: 192.168.136.128(CONNECTED) 2] create /keeper/a
Created /keeper/a
[zk: 192.168.136.128(CONNECTED) 3] delete /keeper/a # 删除就失败了
Authentication is not valid : /keeper/a
[zk: 192.168.136.128(CONNECTED) 4]
PS:要想同时指定多个IP地址,需要这样做:
setAcl /keeper ip:192.168.136.134:crw,ip:192.168.136.128:crwa
auth模式(许多教程是错的!)
- 首先要添加用户
addauth digest <user>:<password>
- 再给某个路径设置权限
setAcl <path> auth::<acl>
(这里acl
千万别设错了!我当时没注意,填了6个1,然后这个节点啥权限都没了) ```bash [zk: localhost:2181(CONNECTED) 9] create /zoo1 Created /zoo1 [zk: localhost:2181(CONNECTED) 10] getAcl /zoo1 ‘world,’anyone : cdrwa [zk: localhost:2181(CONNECTED) 11] setAcl /zoo1 auth:codeleven:cawd [zk: localhost:2181(CONNECTED) 12] getAcl /zoo1 ‘digest,’codeleven:Uj2OCeg9/wrj8mQJU6iGZj/IEcM= : cdwa [zk: localhost:2181(CONNECTED) 13] quit # 退出重进
[zk: localhost:2181(CONNECTED) 0] getAcl /zoo1 # 一开始进来没有任何权限,因为还没认证 Authentication is not valid : /zoo1 [zk: localhost:2181(CONNECTED) 1] addauth digest codeleven:123 # 认证一个错误的密码,正确的是111111 [zk: localhost:2181(CONNECTED) 2] getAcl /zoo1 # 密码错误不会提示,只是无法访问 Authentication is not valid : /zoo1 [zk: localhost:2181(CONNECTED) 3] addauth digest codeleven:111111 # 输入正确的密码 [zk: localhost:2181(CONNECTED) 4] getAcl /zoo1 # 能正常访问 ‘digest,’codeleven:Uj2OCeg9/wrj8mQJU6iGZj/IEcM= : cdwa
注意,**对于auth模式来说, `setAcl` 是不需要指定 `id` 参数的**,Zookeeper会拿**当前已经 `addauth` 的用户作为授权对象**(如果有多个已经 `addauth` 的用户,就创建多个用户的权限):
```bash
[zk: localhost:2181(CONNECTED) 0] create /node 'node'
Created /node
[zk: localhost:2181(CONNECTED) 1] setAcl /node auth:gg:cdraw
Acl is not valid : /node # auth模式下的setAcl,需要先addauth
[zk: localhost:2181(CONNECTED) 2] addauth digest 1:1 # 执行第一遍addauth
[zk: localhost:2181(CONNECTED) 3] setAcl /node auth:gg:cdraw # auth模式下的id字段必须要预留
# 但是内容随意,我给了gg,但是设置的对象是1
[zk: localhost:2181(CONNECTED) 4] getAcl /node
'digest,'1:PndHMdM9kiSsNq89hbofgbMbyE0=
: cdrwa
[zk: localhost:2181(CONNECTED) 5] addauth digest 2:2 # 又addauth了2和3
[zk: localhost:2181(CONNECTED) 6] addauth digest 3:3
[zk: localhost:2181(CONNECTED) 7] setAcl /node auth:mm:cdraw # 这里id也随便给了一个,后面正常授权
[zk: localhost:2181(CONNECTED) 8] getAcl /node
'digest,'3:EQ90fWNTGAcPpfuyFvMse+i1+BE=
: cdrwa
'digest,'1:PndHMdM9kiSsNq89hbofgbMbyE0=
: cdrwa
'digest,'2:eiegrg4ZTLQrNWEMges2RKxiJww=
: cdrwa
[zk: localhost:2181(CONNECTED) 9]
Digest授权模式
setAcl <path> digest:<user>:<password>:<acl>
- 这里的密码需要预先经过
SHA1
以及BASE64
处理,可以在shell 中通过以下命令计算:
算出密文后就可以设置给指定的节点:echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
# 计算密码 echo -n codeleven:111111 | openssl dgst -binary -sha1 | openssl base64 # 获取密码,设置权限列表 setAcl /hadoop digest:codeleven:Uj2OCeg9/wrj8mQJU6iGZj/IEcM=:cdrwa # 现在想要get /hadoop 就需要登录了 addauth digest codeleven:111111 get /hadoop
auth 和 digest的区别
auth需要添加用户;digest需要计算了密文;
在setAcl这步,auth模式只需要设置用户名即可;digest需要给定用户名+密文
认证这一步,两个人都一样,输入的都是明文
多种授权模式
用逗号隔开多个权限
setAcl PATH SCHEME:CONTENT:ACL[,SCHEME:CONTENT:ACL]
CONTENT
指某个模式具体要填写的内容
示例:
setAcl /hadoop digest:codeleven:Uj2OCeg9/wrj8mQJU6iGZj/IEcM=:dra,digest:admin:015uTByzA4zSglcmseJsxTo7n3c=:draw
超级管理员
首先生成超级管理员的digest,操作和
digest
授权模式一样:[root@localhost ~]# echo -n root:root | openssl dgst -binary -sha1 | openssl base64 qiTlqPLK7XM2ht3HMn02qRpkKIE=
编辑
zkServer.sh
脚本,找到下面这两行:158 nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \ 159 "-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
加入一个超级管理配置:
-Dzookeeper.DigestAuthenticationProvider.superDigest=root:qiTlqPLK7XM2ht3HMn02qRpkKIE=
最后变成这样:
158 nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \ 159 "-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \ 160 "-Dzookeeper.DigestAuthenticationProvider.superDigest=root:qiTlqPLK7XM2ht3HMn02qRpkKIE=" \ 161 -XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \ 162 -cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
进入
zkCli.sh
之后,登录超级管理员账号:[zk: localhost:2181(CONNECTED) 1] addauth digest root:root
然后就可以无视权限干任何事情了:
[zk: localhost:2181(CONNECTED) 2] ls / [a0000000003, hadoop, keeper, zoo, zookeeper, zookeeper01] [zk: localhost:2181(CONNECTED) 4] getAcl /zoo 'world,'anyone : [zk: localhost:2181(CONNECTED) 5] deleteall /zoo [zk: localhost:2181(CONNECTED) 6] ls / [a0000000003, hadoop, keeper, zookeeper, zookeeper01] [zk: localhost:2181(CONNECTED) 7]
超级管理员的设置方式和digest授权模式有异曲同工之妙:
超级管理员
- 对象:服务器
- 使用
-Dzookeeper.DigestAuthenticationProvider.superDigest=root:qiTlqPLK7XM2ht3HMn02qRpkKIE=
为当前服务器配置权限
digest
- 对象:某一个节点
- 使用
setAcl
配置权限
版本更新归档
- 删除指定路径下的所有节点,以前是
rmr
,新版本是deleteall
,参考官方Issue