CentOS上 ZooKeeper 资源占用过高的定位与优化
一、快速定位占用来源
- 先看系统层面:用 top/htop 观察 CPU、内存 RSS、I/O wait;用 iotop 检查磁盘写放大;用 netstat/ss 统计连接数。ZooKeeper 数据全在内存、写前先落事务日志,磁盘 I/O 与连接数常是瓶颈。
- 再看服务层面:用四字命令获取关键指标(需本机或有权限访问):
- echo mntr | nc 127.0.0.1 2181 查看 zk_packets_received/sent、zk_avg_latency、zk_outstanding_requests、zk_num_alive_connections 等;
- echo stat | nc 127.0.0.1 2181 查看 Connections、Outstanding;
- echo ruok | nc 127.0.0.1 2181 检查存活。
- 最后看 JVM 层面:开启 GC 日志(示例见下文),用 jstat -gc、jstack、jmap 分析 GC 频率/停顿、线程堆栈、对象分布;若容器化,确保 JVM 感知容器内存限制(如 -XX:+UseContainerSupport)。
二、JVM 与容器内存调优
- 堆大小与稳定性:将 -Xms 与 -Xmx 设为相同值(如 -Xms4G -Xmx4G),避免运行期扩缩堆带来的抖动与停顿。
- 垃圾回收器:优先 G1 GC,设置合理的停顿目标(如 -XX:MaxGCPauseMillis=100-200),并提前触发并发标记(如 -XX:InitiatingHeapOccupancyPercent=30-40),降低 Full GC 风险。
- 直接内存:网络 I/O 常用堆外内存,必要时设置 -XX:MaxDirectMemorySize 上限,并通过 JMX 的 java.nio.BufferPool 监控 Direct Memory 使用趋势。
- 容器场景:添加 -XX:+UseContainerSupport,并按容器总内存设置堆占比(如 -XX:MaxRAMPercentage=75.0),避免超出 cgroup 限制导致被 OOM Killer 终止。
- 落地示例(在 zkServer.sh 的 JVMFLAGS 中设置):
-Xms4G -Xmx4G -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=35 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/zookeeper/heapdump.hprof -Xlog:gc*:file=/var/log/zookeeper/gc.log:time,uptime,level,tags:filecount=10,filesize=10M。
三、ZooKeeper 配置与存储优化
- 基础时序与容错参数:建议 tickTime=2000;根据网络与实例规模设置 initLimit=10、syncLimit=5,避免初始化/同步超时误判。
- 连接与吞吐控制:设置 maxClientCnxns(如 60)限制单客户端连接数,防止个别客户端耗尽资源。
- 数据与日志分离:将 dataDir(快照) 与 dataLogDir(事务日志) 分别挂载到不同磁盘,优先 SSD,显著降低写放大与 I/O 等待。
- 自动清理:开启 autopurge.snapRetainCount=3、autopurge.purgeInterval=1,定期清理旧快照与事务日志,避免磁盘被历史文件占满。
- 示例 zoo.cfg 片段:
tickTime=2000
initLimit=10
syncLimit=5
maxClientCnxns=60
dataDir=/var/lib/zookeeper
dataLogDir=/var/log/zookeeper
autopurge.snapRetainCount=3
autopurge.purgeInterval=1。
四、操作系统与资源限制
- 文件描述符与进程数:提升 ulimit -n(如 65536)、ulimit -u(如 4096),并在 systemd 服务中设置 LimitNOFILE、LimitNPROC,避免“too many open files”。
- 交换分区:生产环境建议 禁用 swap(或 vm.swappiness 调低),避免内存抖动与长 GC 停顿。
- 存储与网络:使用 SSD、保证节点间 低延迟/高带宽 网络,减少选主抖动与写延迟。
五、应用侧与运维实践
- 降低写放大:合并写、减少不必要 Watcher、尽量使用 multi 批量操作,控制 Znodes 数量与数据大小,避免超大节点与频繁创建/删除临时节点。
- 会话管理:合理设置 sessionTimeout,避免过短导致会话风暴、过长导致会话对象堆积。
- 客户端优化:复用 ZooKeeper/Curator 客户端 连接,避免频繁新建/关闭;用 CuratorCache 替代大量原生 Watcher,降低事件堆积与内存压力。
- 监控与告警:持续采集 mntr/stat 指标与 GC 日志,结合 Prometheus/Grafana 建立延迟、吞吐、连接数、GC 停顿等告警基线,出现异常及时滚动重启或扩容。