bigywater.tech
ZooKeeper · 42

ZAB 日志同步:DIFF、TRUNC、SNAP

follower 落后或者数据不一致时,leader 怎么让它追上?文档说有 DIFF、TRUNC、SNAP 三种。这篇逐一制造:略落后、数据丢光、旧 leader 带着未提交的写回来,看 leader 日志里实际选了哪种。

DIFF
follower 略落后:只补缺的事务
SNAP
数据被清空:发整份快照
没看到 TRUNC
旧 leader 的 zxid 来自旧 epoch → 回退成 SNAP

DIFF

实测 · 本机执行输出
  [DIFF] 落后 10 个事务的 follower 重启:追上用时 570 ms
    leader: Synchronizing with Learner sid: 1 maxCommittedLog=0x10000000c minCommittedLog=0x100000001 lastProcessedZxid=0x10000000c peerLastZxid=0x10000
    leader: Sending DIFF zxid=0x10000000c for peer sid: 1
    follower: Peer state changed: following - synchronization - diff

SNAP

实测 · 本机执行输出
  清空数据目录后重启,追上用时 624 ms,znode 数 1005
    leader: Synchronizing with Learner sid: 1 maxCommittedLog=0x1000003e9 minCommittedLog=0x1000001f6 lastProcessedZxid=0x1000003e9 peerLastZxid=0x0
    leader: Sending snapshot last zxid of peer is 0x0, zxid of leader is 0x1000003e9, send zxid of db as 0x1000003e9, 1 concurrent snapshot sync, snapsh
    follower: Peer state changed: following - synchronization - snap

旧 leader 带着未确认的写回来

实测 · 本机执行输出
  旧 leader 被隔离后,发给它的 create /extra:ready = True (它收下并写进了自己的事务日志,但凑不齐多数派)
  隔离 4 秒后各节点: {'z42t-1': 'follower', 'z42t-2': 'leader', 'z42t-3': '不服务'}
  多数派一侧的新 leader: z42t-2 | /extra 在多数派一侧存在吗: False
  网络恢复后各节点: {'z42t-1': 'follower', 'z42t-2': 'leader', 'z42t-3': 'follower'}
    新 leader: Synchronizing with Learner sid: 3 maxCommittedLog=0x200000002 minCommittedLog=0x100000001 lastProcessedZxid=0x200000002 peerLastZxid=0x10000
    新 leader: Cannot send TRUNC to peer sid: 3 peer zxid is from different epoch
    新 leader: Unhandled scenario for peer sid: 3 fall back to use snapshot
    新 leader: Sending snapshot last zxid of peer is 0x100000003, zxid of leader is 0x200000002, send zxid of db as 0x200000002, 1 concurrent snapshot sync
    旧 leader(现 follower): Peer state changed: following - synchronization - snap
  旧 leader 上读 /extra: None | 读 /after: b'2'
  当初那个 create /extra 调用的结果: ConnectionLoss

隔离是用我写的 TCP 代理实现的(节点间通信悄悄丢包)。旧 leader 收下 /extra 之后,因为没有多数派 ack,这条事务从未提交;新 leader 的 epoch 更高,旧 leader 日志里的多余事务在重新加入时被快照覆盖。

分步演示

DIFF / SNAP / TRUNC
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。3 节点伪集群;隔离用 zkl.NetEnsemble(每对节点之间 quorum / 选举连接各经过一个 TCP 代理,丢包不断连);tickTime=500、syncLimit=2
    • 没有验证:同一 epoch 内 follower 多出事务时 TRUNC 的触发条件(没有构造出来)、leader 内存里 committedLog 窗口大小的影响(我早先单独试过落后 3000 个事务,仍是 DIFF,但那次运行的输出没有保留在本文里)、snapshotSizeFactor 对选择 DIFF / SNAP 的影响
    京ICP备2026067502号-1京公网安备11010502063487号