【问题标题】:Create JVM heapdump when K8s healthcheck restarts the pod - no OOM occur当 K8s 健康检查重新启动 pod 时创建 JVM heapdump - 没有发生 OOM
【发布时间】:2020-11-22 15:35:32
【问题描述】:
我有一种情况,突然发生了很长的 GC 暂停,我需要找出突然分配内存的原因。长时间的 GC 暂停(大约 30 秒)导致 pod 连续多次失败 K8s 健康检查,并且 pod 重新启动,实际上没有发生 OOM。我想在 K8s 实际重新启动 pod 之前创建一个堆转储。我意识到应该对一些外部持久挂载进行转储。
我对如何导致堆转储发生的唯一想法是使用 preStop 挂钩。
问题是,当pod因为健康检查失败而重新启动时,是否会触发preStop hook?
也许有更优雅的解决方案?
【问题讨论】:
标签:
java
kubernetes
jvm
heap-dump
kubernetes-health-check
【解决方案1】:
问题是,当 pod 运行时是否会触发 preStop 钩子
由于健康检查失败而重新启动?
是的。根据definition,perStop 挂钩会在容器因 API 请求或管理事件(如活性探测失败、抢占、资源争用等)而终止之前立即运行。
我应该使用 preStop 钩子在 pod 之前捕获 Java Heap Dump
终止?
是的。但是你需要小心,如果容器已经处于终止或完成状态,对 preStop 钩子的调用会失败。当pod is terminated 时,它会在发送 KILL 信号之前等待默认的 30 秒宽限期(如果 PerStop 挂钩未完成,则额外等待 2 秒)。如果 preStop 挂钩需要比默认宽限期允许的时间更长的时间来完成,您必须修改 terminationGracePeriodSeconds 以适应这种情况。
对此有更优雅的解决方案吗?
我不知道。我想通过向 pod 添加一个 empty dir 卷,并配置 JVM 以将堆转储到该目录 command: ["java", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/dumps/oom.bin", "-jar", "yourapp.jar"] 应该可以工作。
为什么上述解决方案会起作用?
当 kubernetes 因为没有响应健康检查而杀死你的容器时,kubernetes 只会重启容器,但不会重新调度 pod,因此不会将其移动到另一个节点。因此,在将 pod 移动到另一个节点之前,不会删除空的 dir 卷。因此,当容器重新启动时,新容器将挂载相同的空目录,该目录将包含上次运行的堆转储。因此,您可以在活动结束后随时kubectl cp 这些文件。复制堆转储文件可能还有其他挑战,但它们是可以解决的。更多信息请查看this。