bigywater.tech
ZooKeeper · 62

GC 停顿对 ZooKeeper 的影响

JVM 的 GC 停顿是 ZooKeeper 运维里最常见的「莫名其妙」:请求突然变慢、会话莫名过期、follower 被踢出。这篇用真实的 Full GC 量一下停顿有多长、请求延迟怎么跟着变,再看 ZooKeeper 自带的停顿监视器靠不靠谱。

14–83 ms
串行 GC 下 6 次 Full GC 的停顿(堆里约 110 MiB 数据)
99 ms
同一时期最大的同步写延迟(基线中位 1.7 ms)
10 ms
JvmPauseMonitor 报告的最大停顿(远小于真实停顿)

制造 GC 停顿

实测 · 本机执行输出
  GC 日志里的 Full GC 停顿(ms):[14.065, 20.646, 35.14, 63.713, 82.943, 66.402, 59.89, 72.183, 64.26, 60.169];普通写延迟中位 1.72 ms,压测期间最大写延迟 99.2 ms
  GC 日志示例: [19.836s][info][gc] GC(82) Pause Full (Diagnostic Command) 124M->115M(285M) 60.169ms

这是为了观察而人为制造的:小堆 + 串行 GC + 手动触发 Full GC。生产环境用 G1 / ZGC 时停顿会短得多,但原理一样——停顿期间 ZooKeeper 的所有线程(包括处理请求和发心跳的)都停了。

ZooKeeper 自带的停顿监视器

实测 · 本机执行输出
  日志里 JVM 停顿相关的行共 1 条,例:
    Starting JVM Pause Monitor with infoThresholdMs:50 warnThresholdMs:200 and sleepTimeMs:500
  mntr:zk_max_jvm_pause_time_ms = 10 | zk_avg_jvm_pause_time_ms = 5.0732 | zk_cnt_jvm_pause_time_ms = 41

停顿的后果(引用前面的实验)

停顿超过 syncLimit × tickTime 时,leader 会把 follower 判定为掉线(第 46 篇);停顿超过会话超时的客户端会话过期(第 13 篇),临时节点消失。所以堆大小、GC 选择、会话超时和 syncLimit 要一起考虑。

分步演示

GC 停顿
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。堆 300 MiB、-XX:+UseSerialGC、GC 日志 -Xlog:gc;树里 10 万个 znode × 500 字节;Full GC 用 jcmd GC.run 触发 6 次
    • 没有验证:G1 / ZGC 的停顿、真实负载下自然发生的 GC、停顿对集群选举的影响(只在第 46 篇用 SIGSTOP 模拟过)、堆更大(数十 GiB)时的停顿
    京ICP备2026067502号-1京公网安备11010502063487号