我遇到了这样的情况,即突然发生了一个非常长的GC暂停,并且我需要找出突然的内存分配的根源。长时间的GC暂停(大约30秒)会导致Pod连续失败几次K8s运行状况检查,并且Pod重新启动,而实际上没有发生OOM。我想在K8s实际重启Pod之前创建一个堆转储。我意识到应该对某些外部持久安装执行转储。
关于如何导致堆转储发生的唯一想法是使用preStop挂钩。 问题是,由于运行状况检查失败而在重新启动Pod时是否触发了preStop挂钩?
也许对此有更优雅的解决方案?
答案 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了解更多信息。