目录
- 背景
- 配置钩子函数
- 验证
背景
在今天的线上业务中,某服务频繁重启。经过排查日志和事件信息,确认是由于 OOM(Out of Memory)导致服务重启。为了方便研发团队定位 OOM 的具体原因,我们决定在 OOM 发生时自动生成内存快照(heap dump),供后续分析使用。
关于 OOM 的详细介绍,可以参考这篇博客:https://www.cnblogs.com/klvchen/articles/12448436.html
JVM 提供了一些参数,能在发生 OOM 时自动生成 heap dump:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/logs/heapdump.hprof
然而,目前还存在两个问题:
- 多次重启可能导致 heap dump 覆盖。例如,如果程序发生了两次 OOM,第二次生成的 heap dump 会覆盖第一次的。
- 这个参数仅适用于 JVM 内部的 OOM,而 K8s 主动重启服务时并不能生成 heap dump。我们通过
kubectl describe pod
查看重启原因,发现是因为健康检查未响应,K8s 自动重启服务。这类情况并非 JVM 的 OOM,因此上述参数无法帮助生成内存快照。
为了解决 K8s 重启时无法导出 heap dump 的问题,我们可以通过配置 preStop
钩子,在容器停止前生成内存快照。相关命令如下:
- 获取进程 ID 为 10 的程序的堆栈信息:
jstack -F 10 >> /logs/thread.dump
- 生成堆内存快照:
jmap -dump:format=b,file=/usr/src/logs/dump.hprof 10
通过这样的优化,既能避免 heap dump 被覆盖,又能在 K8s 重启时生成有用的内存快照,帮助排查问题。
配置钩子函数
在command增加
jstack -F $(jps |grep -v Jps | awk '{print $1}') | tee -a /usr/src/logs/thread.dump && jmap -dump:format=b,file=/usr/src/logs/$(date +'%Y-%m-%d_%H%M%S').hprof $(jps |grep -v Jps | awk '{print $1}')"
lifecycle:preStop:exec:command: ["/bin/sh", "-c", "curl -X PUT \"http://eureka-service:8761/eureka/apps/${POD_NAME}/${POD_IP}:pi6000-mdl-web:8080/status?value=DOWN\" && sleep 30 && jstack -F $(jps |grep -v Jps | awk '{print $1}') | tee -a /usr/src/logs/thread.dump && jmap -dump:format=b,file=/usr/src/logs/$(date +'%Y-%m-%d_%H%M%S').hprof $(jps |grep -v Jps | awk '{print $1}')"]
验证
手动执行 **<font style="color:rgb(244, 116, 102);">kubectl delete pod xxxx</font>**
,可以查看到生成的文件了