一尘不染

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

docker

Java
8/9带来了对-XX:+UseCGroupMemoryLimitForHeap(带有-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

对于仅由单个JVM进程组成的部署,仅使用配额的25%似乎是浪费。因此,现在人们开始设置-XX:MaxRAMFraction=1,因此从理论上讲,JVM可以使用MaxRAM的100%。

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

那么,此配置(-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1)是否对产品甚至最佳实践来说都是安全的?或者我应该还是手拿起-Xmx-Xms-Xss等?


阅读 2073

收藏
2020-06-17

共1个答案

一尘不染

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

请记住,您可能希望为其他过程留出空间,例如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默认情况下处于启用状态,因此所有操作均应立即可用。


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

引入了Java 10
+UseContainerSupport(默认情况下启用),它使JVM在容器环境中使用合理的默认值。自8u191以来,此功能已反向移植到Java
8,这可能允许大量野生Java部署正确配置其内存。

2020-06-17