bigywater.tech
ZooKeeper · 37

zxid 设计

zxid 是 ZooKeeper 里最重要的数字:每个事务一个,全局递增。这篇把它拆开看:高 32 位是什么、低 32 位是什么、换 leader 时怎么变、数据目录里和它相关的文件有哪些。

epoch + counter
zxid = 高 32 位 epoch + 低 32 位 counter
0x100000004 → 0x200000001
换 leader 前后的 zxid(epoch 1 → 2,counter 重来)
acceptedEpoch / currentEpoch
数据目录里保存纪元的两个文件

拆开一个 zxid

实测 · 本机执行输出
  刚选出第一任 leader 后: {'z37-1': '0x100000001 = epoch 1 + counter 1', 'z37-2': '0x100000001 = epoch 1 + counter 1', 'z37-3': '0x100000001 = epoch 1 + counter 1'}
  写 3 个 znode 之后: {'z37-1': '0x100000004 = epoch 1 + counter 4', 'z37-2': '0x100000004 = epoch 1 + counter 4', 'z37-3': '0x100000004 = epoch 1 + counter 4'}
  这 3 个 znode 的 czxid: ['0x100000002', '0x100000003', '0x100000004']

换 leader 之后

实测 · 本机执行输出
  第二任 leader 选出后: {'z37-1': '0x200000001 = epoch 2 + counter 1', 'z37-3': '0x200000001 = epoch 2 + counter 1'}
  再写 2 个之后: {'z37-1': '0x200000003 = epoch 2 + counter 3', 'z37-3': '0x200000003 = epoch 2 + counter 3'}
  /c(第一任)与 /d(第二任)的 czxid: 0x100000004 0x200000002 → 后一任的 zxid 一定更大,即使 counter 更小

磁盘上的痕迹

实测 · 本机执行输出
  z37-1 的 data 目录: ['myid', 'version-2']
  acceptedEpoch = '2'  currentEpoch = '2'
  事务日志文件(文件名是第一条事务的 zxid): ['log.100000001']

分步演示

zxid
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。3 节点伪集群;zxid 来自 srvr 的 Zxid 与 stat 的 czxid
    • 没有验证:counter 达到 2^32 时的行为(没有测)、纪元文件的更新时机(第 38 篇看 epoch 增加的条件)、旧 leader 带着旧 epoch 的请求被拒绝的细节
    京ICP备2026067502号-1京公网安备11010502063487号