Zookeeper的视图结构和标准的UNIX文件系统类似,整个结构也是以树形目录结构展现的。
Zookeeper中的每个节点称为ZNode,每个ZNode上既可以保存数据,也可以挂载子节点。
关于ZNode,不仅可以存储数据,节点本身也有一些状态信息(Stat),本文就来分析下这个Stat信息。
1.Stat信息展示我们随意创建一个节点,可以使用Zookeeper客户端命令,如下所示:
# 1.创建节点/nodefirst 并设置值为:'2022-06-19'
[zk: localhost:2181(CONNECTED) 3] create /nodefirst '2022-06-19'
Created /nodefirst
# 2.获取节点信息
[zk: localhost:2181(CONNECTED) 5] get /nodefirst
2022-06-19 # 节点值
# 以下为Stat信息
cZxid = 0x4
ctime = Sun Jun 19 15:40:10 GMT+08:00 2022
mZxid = 0x4
mtime = Sun Jun 19 15:40:10 GMT+08:00 2022
pZxid = 0x4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 0
我们来逐个看下这些参数的含义
1.1 cZxid/ctimecZxid即create zxid的缩写(创建该节点的事务ID),每一次事务操作都会有一个特定的zxid来代表当前事务ID。
这个值在节点创建成功后是不会变的。
ctime顾名思义也就是 created time的缩写(该节点创建时间),这个值在节点创建成功后也是不会变的。
1.2 mZxid/mtimemZxid即modified zxid的缩写(节点最后一次被更新时的事务ID),每一次更新该节点操作都会修改该值。
mtime对应的也就是 modified time的缩写(节点最后一次被更新时的时间)。
那我们再来测试下,执行下set命令,看下节点信息是否修改
# 修改/nodefirst 值为 '202206191550'
[zk: localhost:2181(CONNECTED) 6] set /nodefirst '202206191550'
cZxid = 0x4
ctime = Sun Jun 19 15:40:10 GMT+08:00 2022
mZxid = 0x5
mtime = Sun Jun 19 15:50:35 GMT+08:00 2022
pZxid = 0x4
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 0
从结果可以看到,cZxid/ctime没有发生变化,而mZxid/mtime则发生了变化,mZxid增加1,mtime则为当前时间
1.3 pZxid表示该节点的子节点列表最后一次被修改时的事务ID。
这个理解起来还是有点抽象的,直接通过示例来展示下。
# 创建节点/nodefirst 的子节点 level2_node1
[zk: localhost:2181(CONNECTED) 7] create /nodefirst/level2_node1 'node1'
Created /nodefirst/level2_node1
# 查看/nodefirst节点信息
[zk: localhost:2181(CONNECTED) 9] get /nodefirst
202206191550
cZxid = 0x4
ctime = Sun Jun 19 15:40:10 GMT+08:00 2022
mZxid = 0x5
mtime = Sun Jun 19 15:50:35 GMT+08:00 2022
pZxid = 0x6
cversion = 1
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 1
在创建子节点之前/nodefirst的pZxid=0x4,创建子节点后pZxid = 0x6
再次创建一个子节点
[zk: localhost:2181(CONNECTED) 10] create /nodefirst/level2_node2 'node2'
Created /nodefirst/level2_node2
[zk: localhost:2181(CONNECTED) 11] get /nodefirst
202206191550
cZxid = 0x4
ctime = Sun Jun 19 15:40:10 GMT+08:00 2022
mZxid = 0x5
mtime = Sun Jun 19 15:50:35 GMT+08:00 2022
pZxid = 0x7
cversion = 2
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 2
pZxid变更为0x7
那么修改子节点的值呢
[zk: localhost:2181(CONNECTED) 12] set /nodefirst/level2_node2 'node22'
cZxid = 0x7
ctime = Sun Jun 19 15:58:23 GMT+08:00 2022
mZxid = 0x8
mtime = Sun Jun 19 15:59:24 GMT+08:00 2022
pZxid = 0x7
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
[zk: localhost:2181(CONNECTED) 13] get /nodefirst
202206191550
cZxid = 0x4
ctime = Sun Jun 19 15:40:10 GMT+08:00 2022
mZxid = 0x5
mtime = Sun Jun 19 15:50:35 GMT+08:00 2022
pZxid = 0x7
cversion = 2
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 2
pZxid=0x7,没有变化。
所以总结下来:节点的pzxid,只有子节点的列表变更了(子节点新增或删除)才会被修改,而子节点内容的变更不会影响pzxid
1.4 cversion/dataVersion/aclVersion节点Stat信息中有三个version。
类型说明备注dataVersion当前节点的内容版本号当前节点的内容被修改的次数。初始值为0,修改一次则增加1。内容如果没有变化,也会增加1.cversion当前节点的子节点列表的变更版本号当前节点的子节点发生新增或删除,则版本号增加1aclVersion当前节点的ACL变更版本号当节点的ACL控制信息,发生一次变更时,版本号增加1综合上面的示例:
/nodefirst值被修改过一次,所以当前dataVersion=1
/nodefirst的子节点被添加过两次,所以当前cversion=2
而ACL信息,一直没有修改过,所以aclVersion=0
1.5 ephemeralOwner创建该临时节点会话的sessionId。
如果当前节点为持久节点,那么ephemeralOwner=0。
当前/nodefirst节点就是持久节点,所以ephemeralOwner = 0x0
1.6 dataLength这个比较容易理解,就是当前节点数据内容的长度
当前/nodefirst值为202206191550,长度就是12
1.7 numChildren表示当前节点的子节点的数量
当前节点/nodefirst有用两个子节点
[zk: localhost:2181(CONNECTED) 14] ls /nodefirst
[level2_node2, level2_node1]
所以/nodefirst 的numChildren = 2
2.节点Stat信息的作用实际大部分时候我们都不会直接使用到节点的Stat信息。
倒是可以使用dataVersion信息的这种特性来做一个乐观锁。
回到Zookeeper.java代码中,来看下其中的setData()方法
/**
* @param path
* the path of the node
* @param data
* the data to set
* @param version
* the expected matching version
*/
public Stat setData(final String path, byte data[], int version)
throws KeeperException, InterruptedException {
}
这里有一个入参version,这个version就是当前我们所希望的节点的dataVersion值。
Zookeeper服务端在处理该请求时,如果发现setData请求所希望version与当前实际的version不同(节点被执行过set操作),则报错。