当K8s healthcheck重新启动pod时,创建JVM heapdump-不发生OOM

时间:2020-08-02 10:04:31

标签: java kubernetes jvm heap-dump kubernetes-health-check

我遇到了这样的情况,即突然发生了一个非常长的GC暂停,并且我需要找出突然的内存分配的根源。长时间的GC暂停(大约30秒)会导致Pod连续失败几次K8s运行状况检查,并且Pod重新启动,而实际上没有发生OOM。我想在K8s实际重启Pod之前创建一个堆转储。我意识到应该对某些外部持久安装执行转储。

关于如何导致堆转储发生的唯一想法是使用preStop挂钩。 问题是,由于运行状况检查失败而在重新启动Pod时是否触发了preStop挂钩?

也许对此有更优雅的解决方案?

1 个答案:

答案 0 :(得分:3)

问题是,当吊舱处于打开状态时,是否会触发preStop挂钩 是否由于健康检查失败而重新启动?

是的。根据{{​​3}},perStop钩子会由于API请求或管理事件(例如,活动探测失败,抢占,资源争用等)而在容器终止之前立即运行。


我应该使用preStop挂钩在pod之前捕获Java堆转储吗 终止?

是的。但是您需要小心,如果容器已经处于终止或完成状态,则对preStop挂钩的调用将失败。当definition时,它会在发送KILL信号之前等待默认的30秒宽限期(如果还没有完成PerStop挂钩,则还要等待2秒)。如果完成preStop挂钩所需的时间超出默认宽限期所允许的时间,则必须修改terminationGracePeriodSeconds以适合此要求。


对此有更优雅的解决方案吗?

我不知道。我猜想是通过向容器中添加pod is terminated卷,并配置JVM来执行到该目录command: ["java", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/dumps/oom.bin", "-jar", "yourapp.jar"]的堆转储。

为什么上述解决方案有效?

当kubernetes因不响应运行状况检查而杀死您的容器时,kubernetes只会重新启动容器,但不会重新安排Pod的时间,因此不会将其移动到另一个节点。因此,直到Pod移至另一个节点之前,不会删除空的目录卷。因此,当容器重新启动时,新容器将安装相同的空目录,该目录将包含前一次运行的堆转储。因此,您可以在事件发生后的任何时间kubectl cp那些文件。复制堆转储文件可能还有其他挑战,但可以解决。检查empty dir了解更多信息。