11.3.3 节点属性与元数据:版本号、时间戳与ACL
本节围绕ZNode的元数据字段展开,理解版本号、时间戳与ACL的含义及其在运维与开发中的使用方式,并给出可执行示例、排错与练习。
1. 版本号(Version)
- dataVersion:节点数据内容版本号。每次setData成功写入都会递增,用于乐观锁与并发控制。
- cversion:子节点列表版本号。每次create/delete子节点都会递增,用于监控子节点变更。
- aclVersion:ACL版本号。每次setACL更新权限都会递增,用于识别权限变更。
示例:并发写入的乐观锁
# 进入客户端(已安装ZooKeeper并启动)
/opt/zookeeper/bin/zkCli.sh -server 127.0.0.1:2181
# 创建节点
create /app/config "v1"
# 查看stat,记录dataVersion
stat /app/config
# 预期:dataVersion = 0
# 正常更新(带版本号)
set /app/config "v2" -v 0
# 预期:成功,dataVersion 变为 1
# 错误更新(旧版本)
set /app/config "v3" -v 0
# 预期:KeeperErrorCode = BadVersion
命令解释
- stat:查看元数据与版本号。
- set -v:指定写入版本号,避免并发覆盖。
2. 时间戳(Timestamp)
- ctime:节点创建时间(毫秒时间戳),用于审计与生命周期分析。
- mtime:节点最后一次数据变更时间,配合dataVersion判断更新频率。
- 时间戳由服务端生成,避免客户端时间漂移导致误判。
示例:定位异常频繁更新
# 查看节点时间戳
stat /app/config
# 输出中关注 ctime/mtime,并与运维时间线对比
3. ACL(Access Control List)
- ACL由scheme、id、perms组成,定义谁可以以何种方式访问节点。
- 常见scheme:world(所有人)、auth(已认证用户)、digest(用户名密码摘要)、ip(IP限制)。
- 常用权限:r读、w写、c创建子节点、d删除子节点、a管理权限。
示例:创建带digest权限的节点
# 进入客户端
/opt/zookeeper/bin/zkCli.sh -server 127.0.0.1:2181
# 添加认证(用户名/密码)
addauth digest admin:Admin@123
# 创建带权限节点
create /secure/app "secret" digest:admin:$(echo -n "admin:Admin@123" | openssl dgst -binary -sha1 | openssl base64):rwca
# 查看ACL
getAcl /secure/app
# 预期:显示 digest 方案与 rwca 权限
命令解释
- addauth:为当前会话添加认证。
- getAcl:查看当前节点ACL。
4. 安装与环境准备(示例环境)
# 下载安装(示例路径)
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz -C /opt
ln -s /opt/apache-zookeeper-3.8.4-bin /opt/zookeeper
# 基础配置
cp /opt/zookeeper/conf/zoo_sample.cfg /opt/zookeeper/conf/zoo.cfg
sed -i 's@dataDir=/tmp/zookeeper@dataDir=/data/zookeeper@' /opt/zookeeper/conf/zoo.cfg
# 启动
/opt/zookeeper/bin/zkServer.sh start
/opt/zookeeper/bin/zkServer.sh status
5. 运维与排错要点
- BadVersion:说明并发写入冲突,使用stat获取最新dataVersion或重试。
- NoAuth:权限不足,检查addauth或ACL是否生效,核对aclVersion是否递增。
- 权限变更未生效:确认setAcl是否成功,检查客户端是否仍使用旧会话。
排错示例
# 查看版本号与ACL是否更新
stat /secure/app
getAcl /secure/app
# 重新设置ACL并验证
setAcl /secure/app world:anyone:r
getAcl /secure/app
6. 练习
1. 创建/app/lock节点,记录dataVersion,模拟两次并发set,观察BadVersion错误。
2. 对/secure/app设置world:anyone:r后,使用未认证会话读取并验证权限。
3. 观察ctime/mtime随setData变化,记录时间差异并解释原因。