bigywater.tech
ZooKeeper · 55

事务日志预分配与 fsync 实测

ZooKeeper 的写延迟主要是什么?答案是 fsync。这篇用三个实验验证:去掉 fsync 会怎样、fsync 慢时日志长什么样、并发时多个事务怎么共用一次 fsync。

11 倍
forceSync=no 对同步写延迟的改善(代价是不保证落盘)
15.0937
异步高并发下平均每次 fsync 提交的事务数
fsync-ing the write ahead log
磁盘变慢时服务端日志里的告警

fsync 的代价

实测 · 本机执行输出
  默认(forceSync=yes)                        同步写 p50 3.02 ms | 异步写    9422 次/秒 | fsync 平均 1.6717 ms / 最大 17 ms | 平均批大小 15.3336 | fsync 警告 0 条
  -Dzookeeper.forceSync=no                 同步写 p50 0.27 ms | 异步写    8074 次/秒 | fsync 平均 0.0 ms / 最大 0 ms | 平均批大小 1.0121 | fsync 警告 0 条

forceSync=no 只用来说明 fsync 占了多少,不建议在生产环境使用。

fsync 慢的告警

实测 · 本机执行输出
  -Dzookeeper.fsync.warningthresholdms=1   同步写 p50 3.00 ms | 异步写    8566 次/秒 | fsync 平均 1.4684 ms / 最大 15 ms | 平均批大小 15.2651 | fsync 警告 726 条
  警告原文示例: fsync-ing the write ahead log in SyncThread:0 took 5ms which will adversely effect operation latency.File size is 671088

批量提交

实测 · 本机执行输出
  300 次串行同步写之后:avg_sync_processor_batch_size = 1.0 , cnt_fsynctime = 301
  再异步写 20000 次之后:avg_sync_processor_batch_size = 15.0937 , cnt_fsynctime = 1345 (20000 个事务只多出 1044 次 fsync)

分步演示

事务日志 fsync
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。单机;fsync 耗时取自 mntr;macOS 上 Java 的 force() 与 F_FULLFSYNC 耗时相近(第 56 篇)
    • 没有验证:预分配大小 preAllocSize 的影响、默认告警阈值 1000 ms 的触发、事务日志放在独立磁盘(第 5 篇只验证了分开存放)、断电后 forceSync=no 的实际丢失量
    京ICP备2026067502号-1京公网安备11010502063487号