跳到正文

ZooKeeper 监控指标与告警 ​

一句话:ZK 的监控不是看进程活没活,而是盯写路径的 fsync、多数派同步和会话这三条链——它们任一变慢,都会先以「锁拿不到、注册表不更新」的形式在业务侧出现。

适用版本:ZooKeeper 3.8 / 3.9;4lw 行为以 3.5.3+ 为准。指标名与默认值以官方文档为准;文中的阈值只是起点,要按自己的基线校准。

相关:01-ZK架构与ZAB协议、04-生产踩坑与运维。

为什么需要 ​

ZK 不在业务请求链路上,故障不会直接报「ZK 挂了」。它先表现为锁等待超时、实例列表不刷新、任务不重新分片;等业务开始重试,ZK 的负载已经被放大了一轮。

只看 ruok 也不够:imok 只说明进程还在,不说明有 quorum,也不说明写延迟正常。需要的是先兆指标——在会话过期和重连风暴之前,就能看到磁盘、请求堆积和副本同步的变化。

核心机制 ​

四个观察面 ​

观察面主要指标反映什么恶化后先出什么事
写路径zk_avg_latency、zk_max_latency、zk_outstanding_requests、zk_last_proposal_size一次写从收到到多数派提交的耗时与排队请求堆积、会话心跳延迟
多数派zk_server_state、zk_followers、zk_synced_followers、zk_pending_syncsLeader 是否在位、Follower 是否跟上选举、写不可用
会话与 Watchzk_ephemerals_count、zk_watch_count、zk_num_alive_connections、zk_open_file_descriptor_count临时节点、通知、连接和 fd 的规模锁丢失、连接被拒
资源磁盘使用率、快照/事务日志增长、JVM GC写路径的物理上限fsync 变慢、进程停顿

zk_followers、zk_synced_followers、zk_pending_syncs 只在 Leader 上输出;zk_open_file_descriptor_count 只在 Unix 平台有。采集时要按角色区分,别把「字段缺失」当成 0。

链一:fsync 慢 → 会话过期 → 重连风暴 ​

ZK 的写要等多数派落盘才提交。磁盘 fsync 一变慢,zk_avg_latency 先升,zk_outstanding_requests 开始堆积;请求线程被占住,会话 ping 也被拖慢。延迟超过协商后的会话超时(默认 2×tickTime ~ 20×tickTime,即 4s–40s),服务端就会让会话过期,删除该会话的全部临时节点。

对业务来说,这一刻锁已经丢了、注册信息已经没了。客户端收到 SessionExpired 后会重连、重新注册 Watch、重新 getData/getChildren,所有客户端同时做,就是重连风暴;读请求放大又推高延迟,形成正反馈。

zk_max_latency 是统计窗口内的最大值(重置时机随版本和快照而变),适合诊断,不适合单独告警;告警看 zk_avg_latency 的趋势和 zk_outstanding_requests 是否持续大于 0。zk_last_proposal_size 突然接近 jute.maxbuffer(默认约 1MB)时,说明有超大写入(大 znode 或多 op 事务),同样会拉高 fsync 和网络耗时。

链二:Leader 失联 → 选举窗口 → 依赖方连锁 ​

Leader 失联后,节点进入 LOOKING,写请求被拒绝;依赖 ZK 的锁、注册、选主客户端会一直等到自己的超时。zk_synced_followers < zk_followers 或 zk_pending_syncs 持续大于 0,说明有 Follower 没跟上——这时 Leader 再挂,落后太多的节点不能立刻参选,选举窗口会被拉长。

选举期间所有写都不可用。上游线程池被阻塞的调用占满,超时后重试又把恢复后的 ZK 打高一波。会话超时设得越长,客户端越晚失败,资源被占住的时间也越长;这是「高可用配置」反过来放大故障的典型。

链三:Watch、临时节点、连接泄漏 ​

zk_watch_count 高不一定是泄漏:可能是大量客户端盯着同一个路径,形成羊群效应,节点一变就同时回调。zk_ephemerals_count 持续增长,说明活着的会话多,或者客户端没关闭连接、临时节点没清理。zk_znode_count 无界增长,常见于按业务 ID 建路径却没有回收。

zk_open_file_descriptor_count 接近上限时,新连接建立失败,表现是客户端连不上而不是 ZK 报错。maxClientCnxns=60(默认)限制单个 IP 到单个服务端的连接数,连接泄漏会先打满这个值。

最小上手 ​

在 zoo.cfg 中放行需要的四字命令(3.5.3+ 默认只放行 srvr):

properties
4lw.commands.whitelist=srvr,ruok,mntr,stat,cons,wchs

采集与验证:

bash
echo mntr | nc 127.0.0.1 2181          # 指标全集
echo srvr | nc 127.0.0.1 2181          # Mode: leader/follower
echo ruok | nc 127.0.0.1 2181          # 期望 imok,只代表进程在
zkServer.sh status                     # 依赖 srvr,白名单要保留它

Prometheus 侧用 zookeeper_exporter,它把 mntr 转成指标(v0.1.10+ 用 -zk-hosts,默认监听 9141):

bash
./zookeeper-exporter \
  -zk-hosts 10.0.0.11:2181,10.0.0.12:2181,10.0.0.13:2181 \
  -listen :9141
curl -s localhost:9141/metrics | grep '^zk_'
yaml
scrape_configs:
  - job_name: zookeeper
    static_configs:
      - targets: ["zk-exporter:9141"]

用 zkCli.sh 做一次端到端确认:

bash
zkCli.sh -server 127.0.0.1:2181
create /monitor/demo value
stat /monitor/demo          # 看 cversion、ephemeralOwner、zxid
get -w /monitor/demo
delete /monitor/demo

生产动作 ​

以下阈值均为起点,按自己的基线校准。告警要带角色(Leader/Follower)和实例,不要只报集群汇总。

告警指标/条件级别先做什么
无 quorumzk_server_state=looking 持续 30s,或全集群 Leader 数为 0P0按 zxid 从大到小恢复节点,先凑多数派
Follower 掉队zk_synced_followers < zk_followers 持续 5mP1查掉队节点的磁盘、网络、GC;不要重启 Leader
同步积压zk_pending_syncs > 0 持续 5mP1同上;此时新 Leader 可能落后
写延迟zk_avg_latency 超过基线 2 倍或持续大于 100msP1查 fsync、磁盘 await、GC
请求堆积zk_outstanding_requests > 0 持续 1m(或大于 10)P1先查磁盘和网络,不要急着重启
会话将过期zk_max_latency 接近协商超时(如 4s)P1诊断 GC 和磁盘;不要靠调大 sessionTimeout 掩盖
磁盘水位dataDir/dataLogDir 大于 70% 预警,大于 85% 严重P1/P0开自动清理或扩盘;不要删 version-2
连接/fdzk_open_file_descriptor_count 大于上限 80%;cons 按 IP 聚合异常P1查连接泄漏、单例、优雅关闭
Watch/临时节点zk_watch_count 或 zk_ephemerals_count 1 小时增长超过 30%P2查羊群、未清理路径、会话泄漏
GCFull GC 停顿大于 1s 或老年代大于 80%P1调堆、查泄漏;停顿超过会话超时会失锁

先分清两种局面:

  • 延迟高但仍可用:zk_server_state 是 leader/follower,synced_followers 等于 followers,写还能成功。此时不要重启任何节点,先限掉非核心写入,查磁盘和 GC。
  • 过半不可用:节点停在 LOOKING,写失败。先恢复 quorum,按 zxid 最大的节点先起、一次一台;不要清空 dataDir,也不要在 quorum 不足时做清理。

处置顺序:确认 quorum 与角色 → 磁盘/GC → 连接与 Watch → 最后才考虑重启单节点。恢复后要预期会话已经过期,临时节点和锁都没了,业务必须重新注册、重新抢锁;不能假设原来的锁还在。

边界 ​

ZK 的优势是强一致和协调原语:写经 ZAB 多数派提交,顺序有保证;Watch 能感知变更;临时节点天然表达「会话活着才算数」,很适合选主、分布式锁、小规模元数据。Curator 把这些模式封装好了,生态成熟。

代价同样明确:所有写都走 Leader 并等待多数派 fsync,写吞吐受磁盘和网络约束;数据常驻内存,单个 znode 默认约 1MB,不适合放大对象;会话靠心跳维持,GC 停顿、网络抖动都会触发过期和重连;Watch 是一次性的,客户端要自己恢复状态。

所以它不该被当成高频配置中心或大流量注册中心。配置变更频繁、需要推送和本地缓存,优先 Nacos;Kubernetes 生态、需要流式 Watch 和 Raft 运维模型,优先 etcd;需要 DNS 和服务健康检查,考虑 Consul。ZK 适合低频、强一致、数据量小的协调场景;把它放在业务数据面或每秒数万次读的注册场景,代价会远高于收益。

讲清楚 ​

ZK 的告警盯三条链。写路径上,事务日志 fsync 变慢会让 avg_latency 和 outstanding_requests 先升,会话心跳被拖过超时,临时节点被删,锁和注册一起失效,客户端再同时重连,读请求放大,延迟更高。多数派这条链看 synced_followers 是否少于 followers、pending_syncs 是否持续大于零;Leader 一挂就进选举,期间不能写,依赖方超时连锁。资源这条链看磁盘只增不减、fd 和 Watch 泄漏。处置时先分清「延迟高但仍有多数派」和「已经 looking」:前者查磁盘和 GC,不要重启;后者先恢复 quorum,按 zxid 从大到小起。ZK 强在顺序一致和临时节点,代价是写受多数派 fsync 约束、会话与重连成本高,所以只放低频协调数据;高频配置和大流量注册交给 Nacos 或 etcd。

把一门技术讲透到既懂也会用