容器化環境中,JVM最佳參數配置實踐

本文分享自華爲雲社區《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的內存作爲最大堆內存

[root@172 ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            7196        2557         299         117        4338        4219
Swap:              0           0           0
[root@172 ~]# docker run -m 512Mi openjdk:8u121 java  -XshowSettings:vm -version VM
VM settings:
    Max. Heap Size (Estimated): 1.56G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_121"
OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-1~bpo8+1-b13)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)

使用-Xms-Xmx指定初始堆內存和最大堆內存,jvm能正常識別

[root@172 ~]# docker run -m 512Mi openjdk:8u121 java -Xms512m -Xmx512m -XshowSettings:vm -version VM
VM settings:
    Min. Heap Size: 512.00M
    Max. Heap Size: 512.00M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_121"
OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-1~bpo8+1-b13)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)

JDK 1.8.0_131版本

使用jdk 1.8.0_131版本鏡像啓動容器,不指定參數,無法識別Cgroups內存限制,使用主機1/4的內存作爲最大堆內存

[root@172 ~]# docker run -m 512Mi openjdk:8u131 java  -XshowSettings:vm -version VM
VM settings:
    Max. Heap Size (Estimated): 1.56G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)

使用-Xms和-Xmx指定初始堆內存和最大堆內存,jvm能正常識別

[root@172 ~]# docker run -m 512Mi openjdk:8u131 java -Xms512m -Xmx512m -XshowSettings:vm -version VM
VM settings:
    Min. Heap Size: 512.00M
    Max. Heap Size: 512.00M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)

在jdk 1.8.0_131版本開始,加入了兩個新參數-XX:+UnlockExperimentalVMOptions-XX:+UseCGroupMemoryLimitForHeap來動態感知容器的Cgroups內存限制,最大堆內存爲Cgroups內存限制的1/4

[root@172 ~]# docker run -m 512Mi openjdk:8u131 java -XX:+UnlockExperimentalVMOptions  -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version VM
VM settings:
    Max. Heap Size (Estimated): 114.00M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
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內存限制的百分比
1 90%
2 50%
3 33%
4 25%
[root@172 ~]# docker run -m 512Mi openjdk:8u131 java -XX:+UnlockExperimentalVMOptions  -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -XshowSettings:vm -version VM
VM settings:
    Max. Heap Size (Estimated): 228.00M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
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

[root@172 ~]# docker run -m 512Mi openjdk:8u191-alpine java  -XshowSettings:vm -version VM
VM settings:
    Max. Heap Size (Estimated): 123.75M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_191"
OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

使用-Xms-Xmx指定初始堆內存和最大堆內存,符合預期

[root@172 ~]# docker run -m 512Mi openjdk:8u191-alpine java -Xms512m -Xmx512m -XshowSettings:vm -version VM
VM settings:
    Min. Heap Size: 512.00M
    Max. Heap Size: 512.00M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_191"
OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

jdk 1.8.0_191版本開始,-XX:MaxRAMFraction-XX:MinRAMFraction被棄用,使用MaxRAMPercentageMinRAMPercentage來修改堆內存在Cgroups內存限制的佔比,參數值是Double類型必須帶小數點

[root@172 ~]# docker run -m 512Mi openjdk:8u191-alpine java -XX:MaxRAMPercentage=50.0 -XX:MinRAMPercentage=50.0 -XshowSettings:vm -version VM
VM settings:
    Max. Heap Size (Estimated): 247.50M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_191"
OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

總結

  • XmsXmx能適應所有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版本開始棄用。
  • MaxRAMPercentageMinRAMPercentage在1.8.0_191版本開始啓用,可以自定義修改堆內存佔容器Cgroups內存限制的百分比。
以上僅適用於容器採用Cgroups v1版本,在Cgroups v2版本中jdk需要1.8.0_372、11.0.16及更高版本才能動態感知Cgroups的內存限制

JVM參數配置建議

  1. 使用容器感知的 JDK 版本。對於使用 Cgroup V1 的集羣,需要升級至 1.8.0_191以及更高版本;對於使用 Cgroup V2 的集羣,需要升級至 1.8.0_372、11.0.16及更高版本。
  2. 由於Java應用使用的總內存不僅僅只有堆內存,還有堆外內存和直接內存。所以設置容器內存上限時必須大於堆內存,應該按照 Java 進程使用的內存量上浮 20%~30% 設置容器內存 limit。如果初次運行程序,並不瞭解其實際內存使用量,可以先設置一個較大的 limit 讓程序運行一段時間,根據監控獲取實際平均使用值對容器內存 limit 進行調整。
  3. 如果在容器內僅運行一個Java 應用程序,則將初始堆大小與最大堆大小最好配置相等。如果不相等,JVM會根據堆內存使用量在Xms與Xmx之間動態修改堆內存大小,導致額外的系統開銷和頻繁的垃圾回收。
  4. 使用-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath參數,在JVM發生OOM時,自動生成dump文件。dump文件路徑最好是持久化掛載路徑避免容器重啓dump文件丟失。

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章