gpt4 book ai didi

docker - Kubernetes 为运行 JVM 的 Pod 抛出 OOM

转载 作者:行者123 更新时间:2023-12-03 02:06:48 26 4
gpt4 key购买 nike

我正在运行包含 JVM (java8u31) 的 Docker 容器。这些容器作为 pod 部署在 kubernetes 集群中。我经常遇到 pod 发生 OOM 的情况,并且 Kubernetes 会杀死 pod 并重新启动它。由于我是 Kubernetes 新手,因此在查找这些 OOM 的根本原因时遇到了问题。

  1. 这是 JVM 参数

    -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xms700M -Xmx1000M  -XX:MaxRAM=1536M  -XX:MaxMetaspaceSize=250M 
  2. 这些容器被部署为有状态集,以下是资源分配

    resources:
    requests:
    memory: "1.5G"
    cpu: 1
    limits:
    memory: "1.5G"
    cpu: 1

    因此分配给容器的总内存与 MaxRam 匹配

  3. 如果我使用 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/etc/opt/jmx/java_pid%p.hprof 这没有帮助,因为 Pod 被杀死并且一旦出现 OOM,就会重新创建并启动,因此 pod 中的所有内容都会丢失

    获取线程或堆转储的唯一方法是通过 SSH 连接到 pod,但我也无法使用该方法,因为 pod 是在 OOM 后重新创建的,因此我无法获取 OOM 时的内存占用情况。我在 OOM 后使用 SSH,这没有多大帮助。

  4. 我还使用 VisualVM、jHat 分析了代码,但找不到大量内存占用,这可能导致 JVM 中运行的线程消耗过多内存或可能存在泄漏。

感谢任何帮助解决 Kubernetes 引发的 OOM。

最佳答案

当 pod 中的应用程序达到您通过 resources.limits.memory 或命名空间限制设置的内存限制时,Kubernetes 会重新启动 pod。

以下文章中介绍了限制资源的 Kubernetes 部分:

Java 应用程序消耗的内存不限于堆的大小,您可以通过指定选项来设置:

-Xmssize Specifies the initial heap size.
-Xmxsize Specifies the maximum heap size.

Java 应用程序需要一些额外的内存用于元空间、类空间、堆栈大小,并且 JVM 本身需要更多的内存来执行垃圾收集、JIT 优化、堆外分配、JNI 代码等任务。很难以合理的精度预测 JVM 的总内存使用情况,因此最好的方法是在实际部署中以正常负载进行测量。

我建议您将 Kubernetes pod 限制设置为双倍 Xmx 大小,检查是否不再出现 OOM,然后逐渐减少到开始出现 OOM 的程度。最终值应位于这些点之间的中间。
您可以从 Prometheus 等监控系统中的内存使用统计中获得更精确的值。

另一方面,您可以尝试通过指定可用选项的数量来限制 java 内存使用,如下所示:

-Xms<heap size>[g|m|k] -Xmx<heap size>[g|m|k]
-XX:MaxMetaspaceSize=<metaspace size>[g|m|k]
-Xmn<young size>[g|m|k]
-XX:SurvivorRatio=<ratio>

有关此内容的更多详细信息,请参阅以下文章:

限制 JVM 内存使用的第二种方法是根据 RAM(或 MaxRAM)的数量计算堆大小。 article 中对其工作原理有很好的解释。 :

The default sizes are based on the amount of memory on a machine, which can be set with the -XX:MaxRAM=N flag.Normally, that value is calculated by the JVM by inspecting the amount of memory on the machine.However, the JVM limits MaxRAM to 1 GB for the client compiler, 4 GB for 32-bit server compilers, and 128 GB for 64-bit compilers.The maximum heap size is one-quarter of MaxRAM .This is why the default heap size can vary: if the physical memory on a machine is less than MaxRAM , the default heap size is one-quarter of that.But even if hundreds of gigabytes of RAM are available, the most the JVM will use by default is 32 GB: one-quarter of 128 GB. The default maximum heap calculation is actually this:

Default Xmx = MaxRAM / MaxRAMFraction

Hence, the default maximum heap can also be set by adjusting the value of the - XX:MaxRAMFraction=N flag, which defaults to 4.Finally, just to keep things interesting, the -XX:ErgoHeapSizeLimit=N flag can also be set to a maximum default value that the JVM should use.That value is 0 by default (meaning to ignore it); otherwise, that limit is used if it is smaller than MaxRAM / MaxRAMFraction .

The initial heap size choice is similar, though it has fewer complications. The initial heap size value is determined like this:

Default Xms = MaxRAM / InitialRAMFraction

As can be concluded from the default minimum heap sizes, the default value of the InitialRAMFraction flag is 64.The one caveat here occurs if that value is less than 5 MB —or, strictly speaking, less than the values specified by -XX:OldSize=N (which defaults to 4 MB) plus -XX:NewSize=N (which defaults to 1 MB).In that case, the sum of the old and new sizes is used as the initial heap size.

本文为您提供了一个很好的起点,可以开始为面向 Web 的应用程序调整 JVM:

关于docker - Kubernetes 为运行 JVM 的 Pod 抛出 OOM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52596383/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com