k8s-pod重启时生成dump文件

k8s环境,有个服务频繁重启,经过排查日志和事件,确认时由于OOM导致服务重启,为了方便研发定位OOM的具体原因,需要在OOM发生时自动生成内存快照(Heap Dump),以供后续研发分析。

方法一:JVM参数

JVM是提供了一些参数,能在发生OOM时自动生成Heap Dump:

  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath=/app/oom/java_heapdump.hprof

然而,目前存在两个问题:

  1. 多次重启会导致heap dump文件覆盖,例如,服务发生了两次OOM,第二次生成的heap dump会覆盖第一次的。
  2. 这个参数仅用于JVM内部的OOM,而k8s主动重启服务时并不能生成heap dump。我们通过kubectl describe pod 查看重启原因,发现是因为健康检查危响应导致的k8s重启服务。这类情况并非JVM的OOM,因此上述参数无法帮助生成内存快照。

所以如果只是单次分析OOM的原因,可以使用JVM的参数,在java启动参数里加上 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/oom/java_heapdump.hprof,再把容器内的/app/oom/目录挂载到node上即可。

1
2
3
4
5
6
7
8
volumes:
- name: dump-file
hostPath:
path: /opt/dump/oom
type: ''
volumeMounts:
- name: dump-file
mountPath: /app/oom

方法二:preStop钩子

为了解决k8s重启时无法导出heap dump和二次覆盖的问题,我们可以通过配置preStop钩子,在容器停止前生成内存快照。相关命令如下:

获取进程ID为10的程序的堆栈信息:

1
jstack -F 10 >> /logs/thread.dump

生成堆内存快照:

1
jmap -dump:format=b,file=/usr/src/logs/dump.hprof 10

通过这样的优化,既能避免heap dump被覆盖,又能在k8s重启时生成有用的内存快照,帮助排查问题。

命令:

1
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}')"

pod的yaml文件配置

加上以下配置:

1
2
3
4
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "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}')"]

验证

手动执行kubectl delete pod,可以查看到生成的文件:

两个命令的区别:

Thank you for your accept. mua!
-------------本文结束感谢您的阅读-------------