线上 OOM 故障排查
凌晨收到告警:服务频繁重启。登录发现 OOM Killer 杀了 Java 进程。本文是完整的排查和修复复盘。
一、告警与发现
- 1.1 监控告警——服务重启次数陡增
- 1.2 第一时间确认——
dmesg | grep -i kill,OOM Killer - 1.3 临时止血——重启服务,增加内存(
-Xmx调大)
二、保留现场
- 2.1 GC 日志——
-Xlog:gc*输出 - 2.2 堆 dump——
-XX:+HeapDumpOnOutOfMemoryError - 2.3 线程 dump——
jstack - 2.4 系统指标——CPU、内存趋势
三、GC 日志分析
- 3.1 Full GC 频率异常——每 30 秒一次
- 3.2 老年代持续增长——内存泄漏的典型特征
- 3.3 GCViewer 可视化
四、MAT 分析堆 dump
- 4.1 Leak Suspects Report——HashMap 占用 2GB
- 4.2 Dominator Tree 追踪——某个缓存 Map 无限增长
- 4.3 Path to GC Roots——由静态变量持有
- 4.4 OQL 查询验证——上千个 Key 从未被清理
五、根因定位
- 5.1 代码审查——本地缓存的
ConcurrentHashMap,只有put没有remove - 5.2 为什么上线时没发现——数据量小的时候不明显
- 5.3 触发条件——业务量增长后缓存膨胀
六、修复方案
- 6.1 短期——加
maximumSize+ LRU 淘汰(Caffeine 替换) - 6.2 长期——切换到 Redis 分布式缓存
- 6.3 监控——添加缓存大小的 JVM 指标
七、预防措施
- 7.1 代码审查规范中加入”缓存必须有淘汰策略”
- 7.2 压测中增加长时间稳定性测试
- 7.3 监控告警——堆内存使用率 > 80% 预警
八、复盘总结
- 在测试环境难以发现的”慢性”内存泄漏
- 缓存使用三原则——大小限制、淘汰策略、过期时间
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 谜思录!