znode 是 ZooKeeper 里唯一的数据结构。它的 stat 里 czxid、mzxid、pzxid、version、cversion、aversion 到底各自什么时候变?路径有什么限制?这篇把每种操作前后的 stat 做 diff,逐项验证。
czxid = 0x2 mzxid = 0x2 pzxid = 0x2 version = 0 cversion = 0 aversion = 0 numChildren = 0 dataLength = 5 ephemeralOwner = 0x0
set /p 新数据 → /p 的变化: {'mzxid': '0x2→0x3', 'version': '0→1', 'dataLength': '5→10', 'mtime': '1790816773889→1790816773896'}
创建子节点 /p/c → /p 的变化: {'pzxid': '0x2→0x4', 'cversion': '0→1', 'numChildren': '0→1'}
再创建 /p/d → /p 的变化: {'pzxid': '0x4→0x5', 'cversion': '1→2', 'numChildren': '1→2'}
修改子节点数据 /p/c → /p 的变化: (无变化)
删除子节点 /p/d → /p 的变化: {'pzxid': '0x5→0x7', 'cversion': '2→3', 'numChildren': '2→1'}
setACL /p → /p 的变化: {'aversion': '0→1'}
子节点 /p/c 的 stat(它没被 /p 的操作影响): {'czxid': 4, 'mzxid': 6, 'version': 1, 'cversion': 0, 'numChildren': 0}这个表是后面很多实验的基础:Watcher 和版本号的条件更新(set -v)都建立在这些字段上。
/p 的 ctime = 1790816773889、mtime = 1790816773896(毫秒);与本机时间差:21 ms(同一台机器)
create '/ok' → Created /ok create '/中文' → Created /中文 create '/a/' → Path must not end with / character create '//a' → Invalid path string "//a" caused by empty node name specified @1 create '/a//b' → Invalid path string "/a//b" caused by empty node name specified @3 create '/.' → Invalid path string "/." caused by relative paths not allowed @1 create '/a/./b' → Invalid path string "/a/./b" caused by relative paths not allowed @3 create '/a/../b' → Invalid path string "/a/../b" caused by relative paths not allowed @4 create 'noslash' → Path must start with / character create '/zookeeper/x' → Created /zookeeper/x create '/a/b' → Node does not exist: /a/b
路径校验发生在 Java 客户端里(请求到达服务端之前)。kazoo 这类客户端会先帮你规范化路径(比如去掉末尾的斜杠),所以这一节用官方的 Java 客户端测;不同语言的客户端对不规范路径的处理可能不同。