本章定位:构建 ZooKeeper 生产级可观测性体系,覆盖 JMX 指标、日志分析、告警策略。
定义与作用
监控是保障 ZooKeeper 集群长期稳定运行的基石。ZooKeeper 通过 JMX(Java Management Extensions)暴露超过 100 个指标,同时输出事务日志和快照日志供问题排查。
监控三个维度:
| 维度 | 工具 | 关键指标 |
|---|---|---|
| 可用性 | JMX + 四字命令 | zk_server_state, zk_num_alive_connections |
| 性能 | JMX | avg_latency, max_latency, outstanding_requests |
| 容量 | JMX | znode_count, watch_count, approximate_data_size |
核心原理
监控架构
采集层(Exporter / 脚本)→ 存储层(Prometheus)→ 展示层(Grafana)→ 告警层(AlertManager)。
完整示例
示例一:启用 JMX 远程监控
场景说明:开启 JMX 远程端口,使外部监控工具能采集指标。
# 启动时添加 JMX 参数
export JMX_PORT=9999
zkServer.sh start
或在 zkServer.sh 中修改 ZOOMAIN:
ZOOMAIN="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
org.apache.zookeeper.server.quorum.QuorumPeerMain"
验证:
# 使用 JConsole 连接 localhost:9999
jconsole localhost:9999
# 或使用 jmxterm
java -jar jmxterm.jar -l localhost:9999
> beans
# domain = org.apache.ZooKeeperService
# 查看所有指标
> get -b org.apache.ZooKeeperService:name0=...
操作前后对比:
| 配置 | ZooKeeper 启动方式 | 监控接入 |
|---|---|---|
| 无 JMX | zkServer.sh start | 仅四字命令可用 |
| 有 JMX | 带 JMX 参数 | JConsole / JMXTerm / Exporter |
示例二:关键 JMX 指标解读
场景说明:采集并解读最重要的几个 JMX 指标。
// 通过 JMX 编程方式获取指标
import javax.management.*;
import javax.management.remote.*;
import java.util.Set;
public class JMXMonitor {
public static void main(String[] args) throws Exception {
String url =
"service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi";
JMXConnector connector =
JMXConnectorFactory.connect(
new JMXServiceURL(url));
MBeanServerConnection mbsc =
connector.getMBeanServerConnection();
// 查询所有 ZooKeeper 相关的 MBean
Set<ObjectName> names = mbsc.queryNames(
new ObjectName("org.apache.ZooKeeperService:*"),
null);
for (ObjectName name : names) {
System.out.println("=== " + name + " ===");
MBeanInfo info = mbsc.getMBeanInfo(name);
for (MBeanAttributeInfo attr :
info.getAttributes()) {
try {
Object value = mbsc.getAttribute(
name, attr.getName());
if (value != null) {
System.out.println(
attr.getName() + " = " + value);
}
} catch (Exception ignored) {}
}
System.out.println();
}
}
}
关键指标表:
| MBean 属性 | 含义 | 正常范围 |
|---|---|---|
| AvgRequestLatency | 平均请求延迟 | < 10ms |
| MaxRequestLatency | 最大请求延迟 | < sessionTimeout |
| OutstandingRequests | 等待中的请求数 | 0 |
| NumAliveConnections | 活跃连接数 | 与客户端数一致 |
| ZnodeCount | ZNode 总数 | 稳定 |
| WatchCount | Watcher 总数 | 稳定 |
| ApproximateDataSize | 数据总大小 | < 1GB |
| FsyncExceedTimeoutCount | fsync 超时次数 | 0 |
操作前后对比:
| 场景 | 指标变化 | 诊断 |
|---|---|---|
| 集群正常 | All metrics stable | — |
| 高负载 | OutstandingRequests > 0 | 扩容或限流 |
| 客户端异常 | NumAliveConnections 波动大 | 修复客户端 |
| 磁盘慢 | FsyncExceedTimeoutCount 增长 | 更换 SSD 或分盘 |
示例三:日志分析
场景说明:通过事务日志和快照日志排查问题。
# 查看事务日志摘要
java -cp zookeeper.jar:lib/slf4j-api.jar \
org.apache.zookeeper.server.LogFormatter \
/data/zookeeper/version-2/log.100000001
输出:
ZooKeeper Transactional Log File with dbid 0
...
6/13/26 10:00:01 AM session 0x10000000001 ...
createSession 30000
6/13/26 10:00:02 AM session 0x10000000001 ...
create '/config,...
6/13/26 10:00:03 AM session 0x10000000001 ...
setData '/config/db.url,#7636a76a,jdbc:mysql://...
# 查看快照文件
java -cp zookeeper.jar:lib/slf4j-api.jar \
org.apache.zookeeper.server.SnapshotFormatter \
/data/zookeeper/version-2/snapshot.100000005
操作前后对比:
| 工具 | 输入 | 输出 | 使用场景 |
|---|---|---|---|
| LogFormatter | 事务日志 | 按时间排序的操作序列 | 追溯数据变更历史 |
| SnapshotFormatter | 快照文件 | 快照时刻的完整数据 | 检查某时刻数据状态 |
示例四:告警策略
场景说明:定义生产环境告警规则。
# Prometheus 告警规则示例
groups:
- name: zookeeper
rules:
- alert: ZookeeperDown
expr: zk_server_state == 0
for: 1m
labels:
severity: critical
annotations:
summary: "ZooKeeper instance down"
- alert: ZookeeperHighLatency
expr: zk_avg_latency > 100
for: 5m
labels:
severity: warning
annotations:
summary: "High avg latency: {{ $value }}ms"
- alert: ZookeeperOutstandingRequests
expr: zk_outstanding_requests > 0
for: 1m
labels:
severity: warning
annotations:
summary: "Outstanding requests: {{ $value }}"
- alert: ZookeeperTooManyConnections
expr: zk_num_alive_connections > 1000
for: 5m
labels:
severity: warning
annotations:
summary: "Too many connections: {{ $value }}"
告警分级:
| 级别 | 示例 | 响应 |
|---|---|---|
| Critical | ZookeeperDown | 立即处理(5 分钟内响应) |
| Warning | HighLatency | 工作日处理 |
| Info | Connections 接近阈值 | 通知关注 |
示例五:审计日志配置与解读
场景说明:启用 ZooKeeper 审计日志,追踪所有数据变更操作,满足安全合规和变更追溯需求。
配置方式(zoo.cfg):
# 启用审计日志(3.6.0+)
audit.enable=true
# 自定义审计日志路径(可选,默认输出到 ZooKeeper 日志文件)
audit.logDir=/var/log/zookeeper/audit
审计日志格式:
# 典型审计日志条目
2026-06-13 10:00:01,123 [Audit] - session=0x10000000001
user=zookeeper ip=192.168.1.10 operation=create
path=/config/db/host result=success
2026-06-13 10:00:02,456 [Audit] - session=0x10000000002
user=super ip=192.168.1.11 operation=setData
path=/config/db/host result=failure
2026-06-13 10:00:03,789 [Audit] - session=0x10000000001
user=zookeeper ip=192.168.1.10 operation=delete
path=/temp/order-001 result=success
日志字段说明:
| 字段 | 含义 | 示例 |
|---|---|---|
| session | 客户端 Session ID(十六进制) | 0x10000000001 |
| user | 操作者用户名(ACL digest 体系) | zookeeper、super |
| ip | 客户端 IP 地址 | 192.168.1.10 |
| operation | 执行的操作类型 | create、setData、delete、setACL |
| path | 操作目标路径 | /config/db/host |
| result | 操作结果 | success / failure(含 ACL 拒绝) |
审计日志与事务日志的区别:
| 维度 | 审计日志 | 事务日志(transaction log) |
|---|---|---|
| 目的 | 安全审计、变更追溯 | 数据持久化、状态恢复 |
| 记录内容 | 用户 + IP + 操作 + 结果 | ZXID + 数据 + 版本号(二进制) |
| 可读性 | 纯文本,人类可读 | 二进制,需 LogFormatter 解析 |
| 完整性 | 仅记录操作元信息 | 完整记录数据变更内容 |
| 文件大小 | 小(每行几十字节) | 大(含完整数据负载) |
| 3.6.0+ | 默认关闭,需显式启用 | 始终开启 |
命令验证:
# 启动 ZooKeeper 后检查审计日志是否生效
grep "Audit" /var/log/zookeeper/audit/audit.log | tail -5
# 输出(示例)
2026-06-13 10:00:05,001 ... operation=create path=/test-node result=success
操作前后对比:
| 维度 | 操作前(audit.enable=false) | 操作后(audit.enable=true) |
|---|---|---|
| 操作追踪 | 无法知道谁做了什么操作 | 精确记录 operator + IP + path |
| 安全合规 | 缺失审计能力 | 满足 SOX / PCI-DSS 等审计要求 |
| 性能影响 | 无 | 极小(异步写入,日志量 < 1KB/操作) |
面试高频题
Q:如何追踪谁修改了 ZooKeeper 的节点?
A:启用审计日志(audit.enable=true)。每条日志记录 session(客户端 ID)、user(ACL 用户名)、ip(来源 IP)、operation(create/setData/delete/setACL)、path(目标路径)、result(成功/失败)。结合 session 字段可串联同一客户端的所有操作序列,满足安全合规和变更追溯需求。与事务日志不同,审计日志是纯文本格式、只记录操作元信息且性能开销极小。
易错场景与面试考点
易错场景
1. 只监控 Leader,忽略 Follower
Follower 也会出问题(磁盘满、OOM),且 Leader 故障后 Follower 接替。所有节点必须同等监控。
2. 事务日志磁盘写满未监控
事务日志写满后 ZooKeeper 拒绝所有写请求。必须监控 version-2 目录所在磁盘的使用率,并配置自动清理策略(snapCount 和 autopurge)。
3. JMX 未加认证直接暴露
生产环境中 JMX 端口直接对外暴露有安全风险。建议:
- 使用 SSL + 用户名密码认证
- 或通过 SSH 隧道转发
- 或仅在内网监控网段开放
面试高频题
Q:ZooKeeper 最重要的 5 个监控指标?
A:
zk_server_state— 角色状态(leader/follower/standalone)zk_avg_latency— 请求延迟zk_outstanding_requests— 积压请求zk_open_file_descriptor_count— 文件描述符zk_packets_received/sent— 请求/响应 QPS
Q:如何处理 ZooKeeper 的 Full GC 问题?
A:
- 通过 JMX 采集 GC 指标(
jstat -gc或 JMXjava.lang:type=GarbageCollector) - 发现 Full GC 频繁时:增大堆内存、切换 G1GC、检查 Ephemeral 节点泄漏
- 极端情况下多个节点同时 Full GC 可能导致集群不可用
Q:Prometheus Exporter 和四字命令采集的区别?
A:Exporter 方式更稳定、支持 Pull 模型、自动对接 Grafana,推荐生产环境使用。四字命令采集适合临时诊断,需要自定义脚本、容易受超时和格式变化影响。
小结
| 要点 | 说明 |
|---|---|
| 三大维度 | 可用性、性能、容量 |
| JMX | 最全面的指标来源,需要显式开启 |
| 四字命令 | 轻量级、运维友好 |
| 日志 | LogFormatter + SnapshotFormatter 深度排查 |
| 审计日志 | 3.6.0+ audit.enable,记录操作者+IP+操作+结果 |
| 告警 | 分级响应:Critical / Warning / Info |
| 全节点监控 | Leader + Follower 同等对待 |
监控体系是生产运维的最后防线。下一章进入面试考点与设计思想,系统梳理 ZooKeeper 的核心答题逻辑。