bigywater.tech
ZooKeeper · 58

文件损坏后的启动失败

数据文件坏了,ZooKeeper 启动时怎么处理?这篇故意制造几种损坏——快照截断、快照清零、快照全丢、日志内容被改、日志尾部撕裂——看它是容错启动、拒绝启动、还是悄悄丢数据。

旧快照兜底
最新快照损坏时回退到旧快照并回放日志,数据不丢
CRC check failed
日志内容被改坏时拒绝启动,不会静默跳过
Last transaction was partial
断电撕裂写:丢弃不完整的最后一条,正常启动

快照损坏

实测 · 本机执行输出
  快照: ['snapshot.253', 'snapshot.331', 'snapshot.534'] 日志: 7 个
  [正常] 启动成功,znode 数 1505
  截断 snapshot.534:175107 → 87553 字节
  [快照截断] 启动成功,znode 数 1505
     日志: Invalid snapshot snapshot.534. len = 2021161080, byte = 120

没有快照

实测 · 本机执行输出
  [快照 0 字节] 启动成功,znode 数 1505

日志损坏

实测 · 本机执行输出
  [无快照(默认)] 启动失败,退出码 1
     日志: java.io.IOException: No snapshot found, but there are log entries. Something is broken!
     日志: Exiting JVM with code 1
  [无快照 + trust.empty=true] 启动成功,znode 数 1505
     日志: java.io.IOException: No snapshot found, but there are log entries. Something is broken!
     日志: Exiting JVM with code 1
     日志: No snapshot found, but there are log entries. This should only be allowed during upgrading.

我最先一次手工破坏日志时,在一个很小的日志文件里看到过「Last transaction was partial」加上 9 个 znode 丢失(1505 → 1496)的结果;但后来用更干净的方法重复,同样的「改坏中间字节」得到的是 CRC 失败。能不能稳定复现那种「丢数据但启动成功」的情形,我没有确认,所以不把它当结论。

集群里的补救

实测 · 本机执行输出
  (a) 破坏 log.523(有效数据约 28688 字节)末尾处偏移 28664 的 16 字节
  [(a) 日志尾部损坏] 启动失败,退出码 1
     日志: java.io.IOException: CRC check failed
     日志: Exiting JVM with code 1
  (b) 破坏 log.555(有效数据约 21038 字节)中间偏移 10519 的 16 字节
  [(b) 日志中间损坏] 启动失败,退出码 1
     日志: java.io.IOException: CRC check failed
     日志: Exiting JVM with code 1

  (c) 模拟断电造成的「撕裂写」:把 log.562(有效数据约 19049 字节)最后 30 字节清零(最后一条事务只写了一半)
  [(c) 最后一条事务写了一半] 启动成功,znode 数 1505
     日志: Last transaction was partial.

分步演示

数据损坏
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。单机,snapCount=300,1500 个 znode;用 truncate / 覆写字节制造损坏;每个场景一个新节点
    • 没有验证:真实磁盘坏块、事务日志中间被截断(而不是改写)、快照与日志不同步(日志缺一段)、检查工具 zkSnapShotToolkit 的校验、更多的 zookeeper.* 恢复开关
    京ICP备2026067502号-1京公网安备11010502063487号