临时节点与持久节点实测:ephemeralOwner 等于会话 id;close() 后几毫秒内消失,进程被 kill -9 要等 6.7 秒的会话超时;服务端重启后同一会话的临时节点仍在;TTL 节点与容器节点需要 extendedTypesEnabled。
顺序节点实测:10 位十进制序号;按父节点各自计数,创建一次 +1、删除不归还、不等于 cversion;8 线程并发创建 400 个得到恰好 0..399;临时顺序节点是分布式锁与队列的基础,会话关闭后序号不连续但相对顺序不变。
内存里的 DataTree 实测:每个 znode 数据 200 字节,200006 个 znode 时 JVM 已用堆 108.5 MiB(约每个 0.52 KiB),读延迟约 0.02 ms;重启从快照重建整棵树 840 ms。
ZooKeeper 客户端连接流程实测(3 节点集群 + kazoo):连接串里的地址被随机挑选;握手确认会话 id(最高字节是服务端 myid)和协商后的超时;服务端被 kill 后客户端 SUSPENDED → 换节点 CONNECTED,会话不变;只写一个地址则无法转移。
会话机制实测:会话 id 最高字节是创建它的服务端 myid;空闲时每 timeout/3 一个 ping(6 s 超时空闲 12 s 共 6 个);leader 的 dump 按过期时间分桶;连在 follower 上的会话在 leader 的 zk_global_sessions 里可见。
会话超时与重连实测:服务端暂停 2 s(< 超时 6 s)客户端无感知;暂停 9 s 后客户端先 SUSPENDED、服务端恢复后收到过期通知 LOST 并建立新会话,临时节点被删除;冻结客户端进程 6.2 s 后服务端删除其临时节点。
会话风暴实测(300 个客户端):建立 300 个会话 166 ms、zxid +300(每个会话一个事务);服务端重启后 300 个客户端全部重连,最慢 11.5 s;会话超时 4 s 而服务端停 6 s 时有 59 个会话过期。
Watcher 实测:数据 watch / 存在 watch / 子节点 watch 各自被哪些操作触发(子节点 watch 不管子节点的数据修改,存在 watch 能监听不存在的节点);事件只带 type、state、path,不带数据;一次性,触发后要重新注册。
Watcher 一次性触发的后果:写 200 次、带重新注册的 watcher 只收到 147 次通知(间隙里的变化没有通知),但重新读取总能拿到最新值;持久 watch(addWatch PERSISTENT / PERSISTENT_RECURSIVE)注册一次持续收到事件,递归模式覆盖整棵子树。
Watcher 风暴实测:300 个客户端 watch 同一个节点,一次 set 后 300 个通知在 51 ms 内到齐(中位 42 ms,对照单个 watcher 6.1 ms);通知后 300 个客户端同时重读重注册共 91 ms,服务端 zk_max_latency 仅 1 ms。
连接数、Watcher 数量和内存的关系实测:400 个空闲连接堆增加 1.0 MiB(约每个 2.6 KiB);20000 个 watch 再增加 5.3 MiB(约每个 278 字节);同一连接对同一路径重复注册只算 1 个。
maxClientCnxns 实测:=5 时同一 IP 开 8 个客户端 5 个成功、3 个连接超时,服务端日志记录「Too many connections from /127.0.0.1 - max is 5」;关闭连接后名额释放;=0 不限制(80 个全部成功);全局上限 zookeeper.maxCnxns=4 时 4 个成功。