请求幂等与重试语义实测(用 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,两端都调才完整。
请求处理链实测:用 jstack 看单机与集群节点的线程(NIO → RequestThrottler → ProcessThread → SyncThread → …),mntr 的平均耗时显示 fsync 是写路径的大头;leader 特有 ProcessThread / LearnerHandler,follower 特有 FollowerRequestProcessor;读在 follower 本地完成。
请求限流实测:20000 次流水线异步写默认 9089 次/秒;globalOutstandingLimit=10 降到 2723;request_throttle_max_requests=10 降到 3299(throttle 队列平均等待 266.0441 ms),=1 降到 492。
集群角色与请求路径实测(3 节点):leader 才有 zk_synced_followers;写通过 follower 要转发给 leader,但延迟差别被 fsync 淹没(5.03 vs 5.90 ms);读在连接的节点本地完成(连 follower 读 2000 次,leader 只多收 1 个包)。
Learner、Follower、Observer 的区别实测:observer 不投票、不算多数派(3 投票节点停 2 个即使还有 2 个 observer 也不能写);observer 接受写并转发给 leader;对写延迟有少量额外开销(5.95 → 7.21 ms)。
Observer 节点实战:连在 observer 上读 2000 次 leader 只多收 1 个包;停掉 2 个 observer 写入不受影响;observer 离线期间错过 2000 个事务,重启 557 ms 内以 DIFF 追上。
Quorum 多数派实测:3 / 4 / 5 个节点各杀不同数量,剩下的能否写——3 节点容忍 1 个,4 节点也只容忍 1 个(多数派 3),5 节点容忍 2 个;因此集群规模取奇数。
5 节点集群与容错数量实测:杀 follower 再杀 leader(2 个故障)后不到 1 秒恢复写入;已确认的 200 个写入全部保留;再杀 1 个失去多数派不可写,启动回 1 个节点(0.7 s)即恢复且数据完整。