记一次生产事故:SkyWalking 导致 Metaspace OOM 问题复盘
本文记录了由SkyWalking引发的Metaspace内存溢出故障处理全过程。事故表现为服务高峰期出现OOM错误,经排查发现是SkyWalking通过byte-buddy动态加载的增强类无法卸载,导致Metaspace持续累积最终溢出。文章详细分析了故障现象、排查思路(保留现场与快速恢复并行)和根因定位过程,指出根本问题是Metaspace容量规划不足。解决方案包括移除SkyWalking Ag
记一次生产事故:SkyWalking 导致 Metaspace OOM 问题复盘
最近线上遇到了一次 Metaspace 内存溢出导致的故障,最终定位到是 SkyWalking 引发的。排查过程虽然曲折,但也积累了不少经验,分享出来供大家参考。
事故经过
某天上班高峰期,线上服务突然不可用,接口全部报错。登录服务器查看日志,发现了大量 java.lang.OutOfMemoryError: Metaspace 错误。
服务重启后,没过多久又再次 OOM。那时候的心情,真的是一言难尽…
排查过程
第一反应:保留现场,快速恢复
发现 OOM 后,第一时间没有直接重启,而是采用了双节点策略:
- 一个节点保留现场,用于排查问题
- 另一个节点先重启恢复业务
这个策略是正确的,避免了业务长时间不可用。
艰难的根因定位
在保留的节点上开始排查。一开始看内存 dump 和业务日志,都没有发现明显异常。日志本身没有给出直接指向根因的线索。
后来在 OOM 堆栈中发现了 sw$ 前缀的类名,这才把怀疑方向指向了 SkyWalking。
查了一下版本,研究了 SkyWalking 的机制,才发现问题所在。
根因分析
SkyWalking 的工作机制
SkyWalking 通过 byte-buddy 对字节码进行增强,这是它正常的工作机制。它会为拦截到的类动态加载大量增强类,而且这些类设计上不会被卸载。
随着服务运行,请求路径不断触发新的代码分支,SkyWalking 持续加载更多增强类,Metaspace 用量随运行时间渐进累积:
服务启动 → SkyWalking 开始拦截字节码,按需加载增强类
↓
每触达一条新代码路径 → 新的增强类被加载进 Metaspace
↓
这些类按机制设计不会被卸载
↓
运行一段时间后,Metaspace 逼近上限
↓
JVM 触发 Full GC 尝试回收 → 类无法卸载 → GC 白跑
↓
Metaspace 耗尽 → OOM
本质是容量规划问题
-XX:MaxMetaspaceSize=256M 从一开始就没有为 SkyWalking 的类加载量预留足够空间。时间越长矛盾越大,OOM 是必然结果,不是偶然。
总结:SkyWalking 正常运行 + 容量规划不足 = 运行一段时间后必然 OOM
解决方案
立即修复
- 移除 SkyWalking Agent(如果暂时不需要链路追踪)
- 调整 Metaspace 大小:
MaxMetaspaceSize=512M或更大
监控告警必须加
这次故障本可以在业务无感知的情况下提前发现。需要接入以下告警:
| 告警项 | 说明 |
|---|---|
| Metaspace 使用率 > 80% | 约 8-9 小时时触发预警,可在业务低谷期处理 |
| Full GC 频率 > 10次/小时 | GC 死循环期间提前触发,比 OOM 早数小时 |
| 接口成功率骤降 | 服务异常时第一时间告警 |
JVM 关键指标(Metaspace、GC、类加载数)必须接入监控平台。
经验总结
做得好的地方
- 双节点策略:保留现场 + 快速恢复业务,两手准备
- 排查路径正确:从日志 → 堆栈 → 研究机制,最终定位根因
需要改进的地方
- 服务恢复后没有第一时间通知相关方:技术团队在埋头分析,但领导和业务方不知道服务已经恢复,信息断层持续了很长时间
排查建议
如果以后遇到类似的 Metaspace OOM 问题,可以按这个顺序排查:
# 1. 确认 OOM 类型
tail -n 200 application.log | grep "OutOfMemoryError"
# 2. 检查是否有 javaagent
ps -ef | grep javaagent
# 3. 查看 Metaspace 使用情况
jstat -gc <pid>
# 4. 如果有 javaagent,优先怀疑 Agent 类加载泄漏
运维建议
- 引入 JVM Agent 类组件时,一定要向开发团队同步其对 JVM 内存的影响
- 生产环境配置基线( JVM 参数、已安装的 Agent 版本)应该是团队共享文档
- 值班人员需要具备
jmap、jstat、日志读取权限
附:Metaspace OOM 应急处理 SOP
【触发条件】接口告警 / 用户反馈服务不可用 / OOM 错误日志
1. 确认 OOM 类型
tail -n 200 /path/to/application.log | grep "OutOfMemoryError"
2. 快速定位根因
→ 检查是否有 -javaagent(SkyWalking/Arthas 等)
→ 检查 MaxMetaspaceSize 配置
3. 保留现场 + 修复重启
jmap -histo:live <pid> > /tmp/heap_histo.txt
修改 JVM 参数(移除问题 javaagent 或调大 MaxMetaspaceSize)
重启服务
4. 重启后立即对外通报
"服务已恢复。根因:xxx。已采取措施:xxx。是否有残留风险:xxx。"
5. 验证稳定性
jstat -gc <pid> 30000 5
观察 Metaspace Used 是否平稳
技术问题的背后往往是管理问题。完善的知识共享机制、权限准备、监控体系、沟通流程,比单纯提升排查技术更能有效减少故障影响。
希望这次复盘对大家有帮助,也欢迎交流讨论。
更多推荐


所有评论(0)