-XX:MaxRAMFraction = 1是否适合在集装箱环境中生产?

ata*_*man 30 java jvm docker

Java 8/9为-XX:+UseCGroupMemoryLimitForHeap(with -XX:+UnlockExperimentalVMOptions)带来了支持.这设置-XX:MaxRAM为cgroup内存限制.默认情况下,JVM分配大约25%的最大RAM,因为-XX:MaxRAMFraction默认值为4.

例:

MaxRAM = 1g
MaxRAMFraction = 4
JVM is allowed to allocate: MaxRAM / MaxRAMFraction = 1g / 4 = 256m
Run Code Online (Sandbox Code Playgroud)

仅使用25%的配额似乎是部署的浪费(通常)由单个JVM进程组成.所以现在人们设置了-XX:MaxRAMFraction=1,所以JVM理论上允许使用100%的MaxRAM.

对于1g示例,这通常会导致堆大小约为900米.这似乎有点高 - JVM或其他东西(如远程shell或进程外任务)没有很多空闲空间.

那么这个配置(-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1)被认为是安全的甚至是最佳实践吗?或者我应该还是伸手接-Xmx,-Xms,-Xss等?

ata*_*man 27

我们做了一些简单的测试,结果表明设置-XX:MaxRAM=$QUOTA-XX:MaxRAMFraction=1导致死载容器负载.JVM分配超过900M的堆,这太多了.-XX:MaxRAMFraction=2似乎安全(ish).

请记住,您可能希望为其他进程留出空间,例如docker exec在容器中获取调试shell()或诊断程序.


编辑:我们已经在一篇文章中详细介绍了我们所学到的内容.报价:

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分配的RAM量进行细粒度控制.由于+UseContainerSupport默认情况下已启用,因此一切都应该开箱即用.

  • 我们也做过类似的测试。我们发现非堆内存分配往往是相当固定的。我们用 Spring Boot 2 测试,我们必须将分数设置为 4,如果我们有大约 500MB 的内存,但是当我们出去到 1G 时,我们可以降下来。对于更大的容器,90% 的空间足以让应用程序正常运行。(容器中有 4GB 内存。) (2认同)

a.l*_*.l. 12

最近的oracle-jdk-8(8u191)带来了以下选项,允许Docker容器用户对将用于Java堆的系统内存量进行更细粒度的控制:

-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage
Run Code Online (Sandbox Code Playgroud)

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

-XX:InitialRAMPercentage -XX:MaxRAMPercentage -XX:MinRAMPercentage这些选项替换不推荐使用的Fraction表单(-XX:InitialRAMFraction,-XX:MaxRAMFraction和-XX:MinRAMFraction).

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