zxid 设计实测:64 位 = epoch(高 32 位)+ counter(低 32 位);写 3 个 znode counter +3;换 leader 后 epoch +1、counter 重新开始(0x100000004 → 0x200000001),后一任的 zxid 一定更大;数据目录里的 acceptedEpoch / currentEpoch 文件记录纪元。
ZXID 的 epoch 与 counter 实测:counter 数事务(create/set/delete 各 +1,multi 整体 +1,新建 + 关闭会话 +2,读 +0);每选出一任 leader epoch +1(2, 3, 4),counter 从 0 开始;没有多数派期间反复选举不增加 epoch,只有成功当选才 +1。
ZAB 一致性协议的三个阶段实测:用杀 leader 后新 leader 与 follower 的日志还原发现 → 同步 → 广播,discovery 约 110 ms、synchronization 约 10 ms;NEWLEADER / UPTODATE 消息可见,发现阶段的消息在 INFO 日志里看不到。
Proposal、事务日志与 Commit 实测:写 500 个 znode,每个 follower 收到 500 个 proposal 和 500 个 commit,leader 提交 500 次;暂停两个 follower 后提案 ack 不齐,数据对读者不可见,恢复后几毫秒内提交可见。
Proposal、Transaction、Commit 的关系实测:用 TxnLogToolkit 读 3 个节点的事务日志,27 条事务逐行完全相同(时间戳、会话 id、cxid、zxid);cxid 是客户端请求序号、zxid 是集群事务序号;multi 是日志里的一条事务。
ZAB 日志同步实测:follower 略微落后 → DIFF;数据被清空 → SNAP(整份快照);旧 leader 带着从未被确认的写重新加入时,新 leader 日志里「Cannot send TRUNC … peer zxid is from different epoch」并回退为 SNAP,那条未确认的写消失。
ZAB 崩溃恢复实测:持续写入时杀 leader 5 次,共 5890 个已确认的写入全部保留(丢失 0 个);每次崩溃时正在进行的请求得到 ConnectionLoss,5 个里有 3 个其实已经写入;恢复后三个节点 zxid 与数据一致。
ZAB 与 Raft 的区别(ZooKeeper 3.9.6 与 etcd 3.7.2 实测):ZooKeeper 本地读没有复现旧读(0/3000);etcd 线性一致读 0/3000、serializable 读 303/3000 旧读;杀 leader 后写中断 etcd 中位 2030 ms vs ZooKeeper 约 445 ms(默认配置)。
Follower 掉线后的恢复实测:离线期间集群仍可写;错过 100 / 3000 / 30000 个写入后重启,leader 都用 DIFF 同步,追上用时 569 / 610 / 809 ms;恢复后数据与 zxid 与 leader 一致。
数据落后 / 无响应节点的处理实测:syncLimit=2 × tickTime=500 ms 时,暂停 follower 后约 898 ms leader 把它判定为掉线(synced_followers 2 → 1),恢复后约 41 ms 重新同步;暂停 0.5 s 则不会被踢出。
网络分区与集群恢复实测(TCP 代理悄悄丢包):隔离 leader 后约 1 s 内所有节点发现并「不服务」,多数派一侧在几秒内选出新 leader(各次差别大);被隔离侧的写得到 ConnectionLoss 且不会保留;恢复后一个 leader + 两个 follower,数据一致。
ZooKeeper 脑裂问题实测(5 节点分成 2 | 3,悄悄丢包):198 次采样里同时报告 leader 的节点数最大为 1;多数派一侧写入成功(5358 ms),少数派一侧的写 ConnectionLoss;恢复后 5 个节点 zxid 相同,少数派的写不保留。