在容器化环境中,-XX:MaxRAMFraction=1是否安全用于生产?

55

Java 8/9 支持 -XX:+UseCGroupMemoryLimitForHeap 参数(需要使用-XX:+UnlockExperimentalVMOptions)。该参数将 -XX:MaxRAM 设置为 cgroup 内存限制值。默认情况下,JVM 将分配最大 RAM 的约25%,因为 -XX:MaxRAMFraction 默认值为 4。

例子:

MaxRAM = 1g
MaxRAMFraction = 4
JVM is allowed to allocate: MaxRAM / MaxRAMFraction = 1g / 4 = 256m

仅使用配额的25%似乎对于通常只包含单个JVM进程的部署来说是浪费。因此,现在人们设置-XX:MaxRAMFraction = 1,因此理论上允许JVM使用最大RAM的100%。

对于1g示例,这通常会导致堆大小约为900m。这似乎有点高 - 没有太多的空闲空间用于JVM或其他诸如远程shell或进程外任务之类的东西。

那么,这种配置(-XX:+ UnlockExperimentalVMOptions -XX:+ UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction = 1 )是否被认为是生产环境中安全的甚至是最佳实践?还是我仍然需要手动选择-Xmx-Xms-Xss等参数?


相关链接:https://dev59.com/86Xja4cB1Zd3GeqPMyfg - atamanroman
你有没有阅读过在容器中运行JVM而不被杀死这篇文章? - Mansuro
2
我做了。有人在评论中问是否将超过90%的可用RAM分配给堆是安全的,作者回答说“据说MaxRAMFraction = 1仍会为其他非堆内存留出一些空间。虽然我没有进行广泛的测试”。似乎不是一个明确的答案。 - atamanroman
8
我知道你在询问Java8/9,但提供一个信息,Java 10增加了一个新选项-XX:MaxRAMPercentage,更具有合理性和灵活性,可以指定最大堆大小。因此,你可以使用-XX:MaxRAMPercentage=80来告诉JVM将容器内存的80%用作堆,而默认的最大堆大小也更接近于容器内存限制。 - Ashutosh
为什么要使用-Xss? - harsha kumar Reddy
2个回答

50

我们进行了一些简单的测试,发现在负载下设置-XX:MaxRAM=$QUOTA-XX:MaxRAMFraction=1会导致容器被杀死。JVM分配了超过900M的堆空间,这太多了。-XX:MaxRAMFraction=2似乎比较安全。

请记住,您可能需要为其他进程留出余地,例如获取调试shell(docker exec)或容器中的诊断。


编辑:我们已经详细记录了我们所学到的内容,可以在文章中查看。以下是重点摘录:

TL;DR:Java内存管理和配置仍然很复杂。虽然自Java 9/8u131以来JVM可以读取cgroup内存限制并相应地调整内存使用情况,但这并不是万能的。您需要知道-XX:+UseCGroupMemoryLimitForHeap的作用,并为每个部署微调一些参数。否则,您可能会浪费资源和金钱,或在最糟糕的时候使容器停止运行。-XX:MaxRAMFraction=1尤其危险。Java 10+带来了许多改进,但仍需要手动配置。为了安全起见,请对您的内容进行负载测试。

以及

最优雅的解决方案是升级到Java 10+。Java 10中弃用了-XX:+UseCGroupMemoryLimitForHeap(11),并引入了-XX:+UseContainerSupport(12),它取代了前者。它还引入了-XX:MaxRAMPercentage(13),它的值介于0和100之间。这允许对JVM可以分配的内存量进行精细控制。由于+UseContainerSupport默认启用,一切都应该可以正常工作。

编辑 #2:我们已经写了更多关于-XX:+UseContainerSupport

Java 10引入了+UseContainerSupport(默认启用),使JVM在容器环境中使用合理的默认值。自Java 8u191以来,该功能已回溯到Java 8,可能允许野外的大部分Java部署正确配置其内存。


2
我们已经进行了类似的测试。我们发现非堆内存分配往往是相当固定的。我们使用Spring Boot 2进行了测试,如果我们的内存约为500MB,我们必须将分数设置为4,但随着我们扩展到1G,我们可以降低分数。对于更大的容器,90%的空间足以使应用程序正常运行。(容器中有4GB内存。) - GreenKiwi
每个容器4GB?你发现这是优化性能的最佳方式吗?我一直在尝试增加负载,但很难找到正确的容器数量和每个容器的内存。 - Alexandre Cassagne
1
括号中的数字是什么意思? - Ruslan Stelmachenko
遗憾的是, xxxRAMPercentage 仍然只影响堆的内存使用情况,而不是整个 JVM 进程的内存消耗(从操作系统/虚拟化程序的角度来看)。 - Sebastian J.

22

最近的oracle-jdk-8(8u191)提供以下选项,允许Docker容器用户更加精细地控制Java堆将使用的系统内存量:

-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage

添加了三个新的JVM选项,以允许Docker容器用户对用于Java堆的系统内存量获得更细粒度的控制:

-XX:InitialRAMPercentage -XX:MaxRAMPercentage -XX:MinRAMPercentage 这些选项替代了弃用的分数形式(-XX:InitialRAMFraction,-XX:MaxRAMFraction和-XX:MinRAMFraction)。

请参见https://www.oracle.com/technetwork/java/javase/8u191-relnotes-5032181.html


1
这些标志在JDK 10+中可用 https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8186248 然而,-XX:+UseContainerSupport现在已经在8u191中可用。 - Fleshgrinder
@Fleshgrinder 我写了一个简单的演示来测试它,在jdk-8u191上运行良好,请参见https://github.com/alex-lx/jdk-8-heap-test - a.l.
我尝试使用-XX:MaxRAMPercentage = 75,但出现了错误,也许需要使用分数?!?有趣的是,该错误本身并没有提及“8u191”的修复方法。 - Fleshgrinder
1
@Fleshgrinder,这可能有些不合理,但在我的测试中,百分比必须是浮点数,例如75.0,并且还应该提到-XX:MaxRAMPercentage-XX:MinRAMPercentage应该一起使用。 - a.l.
1
8u191 中似乎有点问题,但至少在 11 中可以按预期使用。同时要求始终同时使用 max 和 min 也没有太多意义。 - Fleshgrinder
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接