会话超时与重连实测:服务端暂停 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 个成功。
请求幂等与重试语义实测(用 TCP 代理构造响应丢失):ConnectionLoss 后服务端其实已执行;重试 create 得 NodeExists,重试带版本的 set 得 BadVersion,重试 delete 得 NoNode,重试顺序节点会创建出第二个节点;覆盖写重试数据一致但 version 被多推一次。
批量写入与单次写入对比:100 次 create 逐个提交 298 ms,一个 multi 6.2 ms(快 48 倍);multi 原子(失败全部回滚)、共用一个 zxid、可用 check 做版本条件;整个请求受 ~1 MiB 限制。
大 value 对性能的影响:1 KiB~100 KiB 写延迟都约 3 ms(被 fsync 主导),1000 KiB 写 4.50 ms / 读 0.73 ms;1000 次 set 100 KiB 使事务日志增长 143 MiB;watch 通知不带数据,但重读要读整份。
大量 ZNode 的性能问题:get_children 延迟随子节点数线性增长(1000 个 0.7 ms → 30000 个 9.3 ms);分到 100 个父节点下每个只要 0.24 ms;删除非空父节点要递归;官方 Java 客户端对超过 jute.maxbuffer 的 get_children 响应直接断开。
Jute 最大消息大小实测:默认 jute.maxbuffer=1048575 字节,数据 1048500 字节成功、1048560 字节 ConnectionLoss,服务端日志记录「Len error」;服务端调到 4 MiB 后 kazoo 能读写 3 MiB,官方 Java 客户端没调大时读取会 ConnectionLoss,两端都调才完整。