Docker 和 DC/OS 的 JVM 优化

JVM Optimizations for Docker and DC/OS

我正在将一个裸机 java 应用程序 (jar jdk8) 移动到 docker 个容器和 DC/OS。我注意到 dockers 上有一个奇怪的模式,我们将 -XMX 设置为 32 gig 并分配了一个 36 gig docker 容器。每隔几个小时左右,应用程序就会在旧代内存分配中出现峰值,并且 GC 会在尝试进行堆转储时陷入循环(maxing CPU)。

是否有任何优化或我可以使用的东西来了解为什么在 1-5 秒的时间间隔内我们的峰值如此之快? Docker 和 JVM 是否有任何我可能需要注意的问题?

我们正在使用默认 GC

仅供日后参考:

我们正在使用 JDK 8,似乎 Oracle 最近刚刚添加了一些使用 Docker 的实验性标志。我相信这种情况可能是当 GC 分配线程时它没有考虑 cgroup 的 docker 线程数。实验性标志似乎已经修复了我们的 "off the rails issue"

https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits

如果您有可能使用像 DC/OS.[=16 这样的容器平台,通常您会希望避免这种内存超过 30GB 的巨大应用程序,并将您的应用程序拆分成内存需求较少的较小部分=]

关于 GC 和堆大小的一般信息:如果堆大小很大,则 Full GC 可能需要很长时间。我个人经历过完整的 GC 冻结长达一分钟或更长时间,堆大小与您提到的 30GB 非常相似。

关于容器中的 Java:JVM 实际上需要比您配置的 -Xmx 更多的内存。因此,如果您在 DC/OS (Marathon) 应用程序中指定 2GB 的内存限制,则不能设置 -Xmx2G,因为此内存限制是硬限制。如果容器内的进程超过这些内存限制,容器将被终止。由于 JVM 将保留比配置的 -Xmx 中更多的临时内存,这确实很可能发生。一般来说,我建议使用大约 75% 的已配置内存作为 -Xmx.

的值

您可以查看支持 -XX:+UseCGroupMemoryLimits 的更新的 JRE 版本。这是使用 cgroup 容器限制内存消耗的 JRE 标志,请参阅 https://developers.redhat.com/blog/2017/04/04/openjdk-and-containers/ 了解更多信息。