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

2022-08-31 23:39:44

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

例:

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

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

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

那么,此配置()是否被视为对生产甚至最佳实践是安全的?还是我应该还是手动选择 、等?-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1-Xmx-Xms-Xss


答案 1

我们做了一些简单的测试,显示了该设置,并导致在负载下杀死容器。JVM 分配了超过 900M 的堆,这太多了。 看起来很安全。-XX:MaxRAM=$QUOTA-XX:MaxRAMFraction=1-XX:MaxRAMFraction=2

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


编辑:我们已经在一篇文章中详细写下了我们学到的东西。货币报价:

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

最优雅的解决方案是升级到Java 10+。Java 10 弃用 (11) 并引入了 (12),后者取代了它。它还引入了 (13),其值介于 0 和 100 之间。这允许对允许 JVM 分配的 RAM 量进行细粒度控制。由于 默认情况下启用,因此一切正常。-XX:+UseCGroupMemoryLimitForHeap-XX:+UseContainerSupport-XX:MaxRAMPercentage+UseContainerSupport


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

引入了 Java 10(缺省启用),这使得 JVM 在容器环境中使用 sane 缺省值。自 8u191 以来,此功能已向后移植到 Java 8,这可能允许大量 Java 部署正确配置其内存。+UseContainerSupport


答案 2

最近的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


推荐