我的 Java 微服务在 AWS EC2 实例上托管的 k8s 集群中运行。
我在 K8s 集群中运行了大约 30 个微服务(nodejs 和 Java 8 的良好组合)。我面临一个挑战,我的 Java 应用程序 pod 意外重启,这导致应用程序 5xx 计数增加。
为了调试这个,我在 pod 和应用程序中启动了一个 newrelic 代理,并找到了下图:
在我可以看到的地方,我的 Xmx 值为 6GB,我的用途是最大 5.2GB。
这清楚地表明 JVM 没有跨越 Xmx 值。
但是当我描述 pod 并寻找最后一个状态时,它会显示“原因:错误”和“退出代码:137”
然后在进一步调查中,我发现我的 Pod 平均内存使用一直接近其极限。(分配的 9Gib,使用 ~9Gib)。我无法理解为什么 Pod 中的内存使用率如此之高,尽管我只有一个进程在运行((JVM),而且这也受到 6Gib Xmx 的限制。
当我登录到我的工作节点并检查 docker 容器的状态时,我可以看到该应用程序的最后一个容器具有 Exited 状态并显示“容器以非零退出代码 137 退出”
我可以看到wokernode内核日志为:
这表明内核正在终止我在容器内运行的进程。
我可以看到我的工作节点中有很多可用内存。
我不确定为什么我的 pod 一次又一次地重新启动,这是 k8s 的行为还是我的基础设施中的一些欺骗性行为。这迫使我再次将我的应用程序从容器移动到虚拟机,因为这会导致 5xx 计数增加。
编辑:将内存增加到 12GB 后,我收到了 OOM。
我不确定为什么 POD 会因为 OOM 而被杀死
虽然 JVM xmx 只有 6 GB。
需要帮忙!
最佳答案
一些较旧的 Java 版本(Java 8 u131 版本之前)无法识别它们正在容器中运行。因此,即使您使用 -Xmx 为 JVM 指定最大堆大小,JVM 也会根据主机的总内存而不是容器可用的内存来设置最大堆大小,然后当进程尝试分配超过其限制的内存时(在 pod/部署规范中定义)您的容器正在被 OOMKilled。
在本地运行 K8 集群中的 Java 应用程序时,这些问题可能不会出现,因为 pod 内存限制和本地机器总内存之间的差异不大。但是,当您在具有更多可用内存的节点上在生产环境中运行它时,JVM 可能会超过您的容器内存限制并且会被 OOMKilled。
从 Java 8(u131 版本)开始,可以让 JVM 成为“容器感知”,以便识别由容器控制组 (cgroups) 设置的约束。
对于 Java 8 (来自 U131 版本)和 Java9 您可以将此实验标志设置为 JVM:
-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap
它将根据您的容器 cgroups 内存限制设置堆大小,该限制在 pod/deployment 规范的容器定义部分中定义为“资源:限制”。
在 Java 8 中仍然可能存在 JVM 的堆外内存增加的情况,因此您可能会监视它,但总体而言,这些实验标志也必须处理它。
来自 Java 10 这些实验性标志是新的默认值,可以使用此标志启用/禁用:
-XX:+UseContainerSupport
-XX:-UseContainerSupport
关于docker - Kubernetes pods 重启问题异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51474223/