docker JVM配置自动感知分配内存

docker JVM配置自动感知分配内存

想象一下,你有一个32GB内存的节点,你想使用Docker运行一个限制为1GB的Java应用程序。如果未提供-Xmx参数,则JVM将使用其默认配置:

  • JVM将检查总可用内存。因为JVM不知道Linux容器(特别是限制内存的控制组),所以它认为它在主机上运行并且可以访问完整的 32GB可用内存。
  • 默认情况下,JVM将使用MaxMemory / 4,在这种情况下为8GB(32GB / 4)。
  • 随着堆大小的增长并超过1GB,容器将被Docker杀死。

早期的Docker Java采用者有一段时间试图理解为什么他们的JVM在没有任何错误消息的情况下崩溃。要了解发生了什么,你需要检查被杀死的Docker容器,在这种情况下,你会看到一条消息说“OOM被杀 ”(OutOf Memory)。

当然,一个明显的解决方案是使用Xmx参数修复JVM的堆大小,但这意味着您需要控制内存两次,一次在Docker中,一次在JVM中。每当你想要做出改变时,你必须做两次。不理想。

此问题的第一个解决方法是使用Java 8u131和Java 9发布的版本,我说解决方法是因为你必须使用心爱的-XX:+ UnlockExperimentalVMOptions参数。如果您从事金融服务,我相信您很乐意向您的客户或您的老板解释这是明智之举。

然后你必须使用-XX:+ UseCGroupMemoryLimitForHeap,这将告诉JVM检查控制组内存限制以设置最大堆大小。

最后,您必须使用-XX:MaxRAMFraction来决定可以为JVM分配的最大内存部分。不幸的是,这个参数是一个自然数。例如,将Docker内存限制设置为1GB,您将拥有以下内容:

-XX:MaxRAMFraction = 1最大堆大小为1GB。这不是很好,因为你不能给JVM 100%的允许内存。

-XX:MaxRAMFraction = 2最大堆大小为500MB。那更好但现在看来我们浪费了很多内存。

-XX:MaxRAMFraction = 3最大堆大小为250MB。你正在支付1GB的内存,你的Java应用程序可以使用250MB。这有点荒谬

-XX:MaxRAMFraction = 4 太小。

基本上,控制最大可用RAM的JVM标志被设置为分数而不是百分比,这使得很难设置能够有效利用可用(允许)RAM的值。

我们专注于内存,但同样适用于CPU。你需要使用像这样的参数

-Djava.util.concurrent.ForkJoinPool.common.parallelism = 2

控制应用程序中不同线程池的大小。2表示两个线程(最大值将限制为主机上可用的超线程数)。

总而言之,使用Java 8u131和Java 9,你会有类似的配置:

-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap
-XX:MaxRAMFraction=2
-Djava.util.concurrent.ForkJoinPool.common.parallelism=2

幸运的是Java 10来救援。首先,您不必使用可怕的实验功能标志。如果在Linux容器中运行Java应用程序,JVM将自动检测控制组内存限制。否则,您只需添加-XX:-UseContainerSupport。

然后,您可以使用-XX控制内存:InitialRAMPercentage,-XX:MaxRAMPercentage和-XX:MinRAMPercentage。比如

  • Docker内存限制:1GB
  • -XX:InitialRAMPercentage = 50
  • -XX:MaxRAMPercentage = 70

您的JVM将从500MB(50%)堆大小开始,并将增长到700MB(70%),在容器中最大可用内存为1GB。

猜你喜欢

转载自blog.csdn.net/yucaifu1989/article/details/108106792