记一次生产事故: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-n200application.log|grep"OutOfMemoryError"# 2. 检查是否有 javaagentps-ef|grepjavaagent# 3. 查看 Metaspace 使用情况jstat-gc<pid># 4. 如果有 javaagent,优先怀疑 Agent 类加载泄漏运维建议
- 引入 JVM Agent 类组件时,一定要向开发团队同步其对 JVM 内存的影响
- 生产环境配置基线( JVM 参数、已安装的 Agent 版本)应该是团队共享文档
- 值班人员需要具备
jmap、jstat、日志读取权限
附:Metaspace OOM 应急处理 SOP
【触发条件】接口告警 / 用户反馈服务不可用 / OOM 错误日志1. 确认 OOM 类型tail-n200/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>300005观察 Metaspace Used 是否平稳技术问题的背后往往是管理问题。完善的知识共享机制、权限准备、监控体系、沟通流程,比单纯提升排查技术更能有效减少故障影响。
希望这次复盘对大家有帮助,也欢迎交流讨论。