容器化环境中,JVM最佳参数设置实践

打印 上一主题 下一主题

主题 879|帖子 879|积分 2637

本文分享自华为云社区《Java应用容器化参数设置最佳实践》,作者:可以交个朋友。
简介

当你在物理机或者假造机上设置 JVM 参数时,JVM会默认使用主机上1/4的内存作为堆内存,你也可以选择使用-Xmx/-Xms 来指定 Java 堆内存大小。在容器化环境中,每个容器实例的内存大小由Cgroups设置决定,而低版本JVM对Cgroups的支持是不太友好的。本文重要探讨JVM最佳参数设置
JDK与Cgroups的适配关系

JDK 1.8.0_131之前的版本

使用jdk 1.8.0_121版本镜像启动容器实例,不指定参数情况下,无法识别Cgroups内存限制,使用主机1/4的内存作为最大堆内存
  1. [root@172 ~]# free -m
  2.                total        used        free      shared  buff/cache   available
  3. Mem:            7196        2557         299         117        4338        4219
  4. Swap:              0           0           0
  5. [root@172 ~]# docker run -m 512Mi openjdk:8u121 java  -XshowSettings:vm -version VM
  6. VM settings:
  7.     Max. Heap Size (Estimated): 1.56G
  8.     Ergonomics Machine Class: server
  9.     Using VM: OpenJDK 64-Bit Server VM
  10. openjdk version "1.8.0_121"
  11. OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-1~bpo8+1-b13)
  12. OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
复制代码
使用-Xms和-Xmx指定初始堆内存和最大堆内存,jvm能正常识别
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u121 java -Xms512m -Xmx512m -XshowSettings:vm -version VM
  2. VM settings:
  3.     Min. Heap Size: 512.00M
  4.     Max. Heap Size: 512.00M
  5.     Ergonomics Machine Class: server
  6.     Using VM: OpenJDK 64-Bit Server VM
  7. openjdk version "1.8.0_121"
  8. OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-1~bpo8+1-b13)
  9. OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
复制代码
JDK 1.8.0_131版本

使用jdk 1.8.0_131版本镜像启动容器,不指定参数,无法识别Cgroups内存限制,使用主机1/4的内存作为最大堆内存
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u131 java  -XshowSettings:vm -version VM
  2. VM settings:
  3.     Max. Heap Size (Estimated): 1.56G
  4.     Ergonomics Machine Class: server
  5.     Using VM: OpenJDK 64-Bit Server VM
  6. openjdk version "1.8.0_131"
  7. OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
  8. OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
复制代码
使用-Xms和-Xmx指定初始堆内存和最大堆内存,jvm能正常识别
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u131 java -Xms512m -Xmx512m -XshowSettings:vm -version VM
  2. VM settings:
  3.     Min. Heap Size: 512.00M
  4.     Max. Heap Size: 512.00M
  5.     Ergonomics Machine Class: server
  6.     Using VM: OpenJDK 64-Bit Server VM
  7. openjdk version "1.8.0_131"
  8. OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
  9. OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
复制代码
在jdk 1.8.0_131版本开始,加入了两个新参数-XX:+UnlockExperimentalVMOptions和-XX:+UseCGroupMemoryLimitForHeap来动态感知容器的Cgroups内存限制,最大堆内存为Cgroups内存限制的1/4
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u131 java -XX:+UnlockExperimentalVMOptions  -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version VM
  2. VM settings:
  3.     Max. Heap Size (Estimated): 114.00M
  4.     Ergonomics Machine Class: server
  5.     Using VM: OpenJDK 64-Bit Server VM
  6. openjdk version "1.8.0_131"
  7. OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
  8. OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
复制代码
新参数-XX:+UnlockExperimentalVMOptions和-XX:+UseCGroupMemoryLimitForHeap虽然能动态感知Cgroups内存限制,但是却只能使用1/4,无法修改。此时可以使用另外两个参数-XX:MaxRAMFraction和-XX:MinRAMFraction,参数值必须为整数,取值参考如下表格:
MaxRAMFraction/MinRAMFraction取值Cgroups内存限制的百分比190%250%333%425%
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u131 java -XX:+UnlockExperimentalVMOptions  -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -XshowSettings:vm -version VM
  2. VM settings:
  3.     Max. Heap Size (Estimated): 228.00M
  4.     Ergonomics Machine Class: server
  5.     Using VM: OpenJDK 64-Bit Server VM
  6. openjdk version "1.8.0_131"
  7. OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
  8. OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
复制代码
最大堆内存为Cgroups内存限制的50%,符合预期
JDK 1.8.0_191版本

使用jdk 1.8.0_191版本镜像启动容器,不指定参数,jvm能动态感知Cgroups内存限制,最大堆内存为Cgroups内存限制的1/4
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u191-alpine java  -XshowSettings:vm -version VM
  2. VM settings:
  3.     Max. Heap Size (Estimated): 123.75M
  4.     Ergonomics Machine Class: server
  5.     Using VM: OpenJDK 64-Bit Server VM
  6. openjdk version "1.8.0_191"
  7. OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0)
  8. OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
复制代码
使用-Xms和-Xmx指定初始堆内存和最大堆内存,符合预期
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u191-alpine java -Xms512m -Xmx512m -XshowSettings:vm -version VM
  2. VM settings:
  3.     Min. Heap Size: 512.00M
  4.     Max. Heap Size: 512.00M
  5.     Ergonomics Machine Class: server
  6.     Using VM: OpenJDK 64-Bit Server VM
  7. openjdk version "1.8.0_191"
  8. OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0)
  9. OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
复制代码
jdk 1.8.0_191版本开始,-XX:MaxRAMFraction和-XX:MinRAMFraction被弃用,使用MaxRAMPercentage和MinRAMPercentage来修改堆内存在Cgroups内存限制的占比,参数值是Double类型必须带小数点
  1. [root@172 ~]# docker run -m 512Mi openjdk:8u191-alpine java -XX:MaxRAMPercentage=50.0 -XX:MinRAMPercentage=50.0 -XshowSettings:vm -version VM
  2. VM settings:
  3.     Max. Heap Size (Estimated): 247.50M
  4.     Ergonomics Machine Class: server
  5.     Using VM: OpenJDK 64-Bit Server VM
  6. openjdk version "1.8.0_191"
  7. OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0)
  8. OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
复制代码
总结


  • Xms和Xmx能顺应所有JDK版本,但不能动态感知容器的Cgroups限制,且参数优先级最高,与其他参数一起设置时,其他参数不生效。
  • -XX:+UnlockExperimentalVMOptions和-XX:+UseCGroupMemoryLimitForHeap在1.8.0_131版本开始启用,能动态感知容器的Cgroups限制,但最大堆内存只能使用容器Cgroups内存限制的1/4。
  • -XX:MaxRAMFraction和-XX:MinRAMFraction在1.8.0_131版本开始启用,可以修改堆内存占容器Cgroups内存限制的百分比,但百分比的值不能自由指定(比如不能指定40%),在1.8.0_191版本开始弃用。
  • MaxRAMPercentage和MinRAMPercentage在1.8.0_191版本开始启用,可以自界说修改堆内存占容器Cgroups内存限制的百分比。
以上仅适用于容器采用Cgroups v1版本,在Cgroups v2版本中jdk需要1.8.0_372、11.0.16及更高版本才能动态感知Cgroups的内存限制JVM参数设置建议


  • 使用容器感知的 JDK 版本。对于使用 Cgroup V1 的集群,需要升级至 1.8.0_191以及更高版本;对于使用 Cgroup V2 的集群,需要升级至 1.8.0_372、11.0.16及更高版本。
  • 由于Java应用使用的总内存不仅仅只有堆内存,另有堆外内存和直接内存。所以设置容器内存上限时必须大于堆内存,应该按照 Java 历程使用的内存量上浮 20%~30% 设置容器内存 limit。如果初次运行程序,并不相识其现实内存使用量,可以先设置一个较大的 limit 让程序运行一段时间,根据监控获取现实均匀使用值对容器内存 limit 举行调整。
  • 如果在容器内仅运行一个Java 应用程序,则将初始堆大小与最大堆大小最好设置相等。如果不相等,JVM会根据堆内存使用量在Xms与Xmx之间动态修改堆内存大小,导致额外的体系开销和频繁的垃圾采取。
  • 使用-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath参数,在JVM发生OOM时,自动天生dump文件。dump文件路径最好是持久化挂载路径克制容器重启dump文件丢失。
点击关注,第一时间相识华为云奇怪技术~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表