前言
將 Java 應用容器化雖然更好地解決了可移植性問題,但也存在著一些不友好的情況,比如低版本的JDK(低於Java 8u131)並不能識別 CGroup 資源限制。這將導致JVM讀取的是宿主機的全部CPU和記憶體,一但容器使用資源超過限制則會被 docker 殺死。
在 kubernetes 中,我們會顯示在 yaml 檔案中配置CPU、記憶體請求和限制,我們希望容器中的JVM程式能夠自動識別到 CGroup 資源限制,獲取到正確的記憶體和CPU資訊從而自行動態調整。
JVM 引數配置
以下操作皆在一臺 4C 16G 伺服器上進行。
版本低於 8u131
JDK 版本低於 8u131 版本的 JVM 不會自動識別到 CGroup 資源限制,需要手動設定初始堆大小以及最大堆大小,否則會按照宿主機的全部記憶體設定預設值:
- 配置最大堆大小
-Xmx
,預設值:記憶體的1/4 - 配置初始堆大小
-Xms
,預設值:記憶體的1/64
未配置JVM引數
可以看到 Max. Heap Size (Estimated): 3.48G
,未能正確識別 CGroup 資源限制
$ docker run --rm -m 2GB openjdk:8u121-alpine java -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 3.48G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (IcedTea 3.3.0) (Alpine 8.121.13-r0)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
配置JVM引數
配置 -Xmx
和 -Xms
後即可達到我們想要的結果
$ docker run --rm -m 2GB openjdk:8u121-alpine java -XshowSettings:vm -Xmx2000m -Xms2000m -version
VM settings:
Min. Heap Size: 1.95G
Max. Heap Size: 1.95G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (IcedTea 3.3.0) (Alpine 8.121.13-r0)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
8u131 及以上版本
從 8u131 版本開始支援 UseCGroupMemoryLimitForHeap
和 MaxRAMFraction
這兩個選項,用 CGroupMemory
的大小作為 JVM heap size,MAXRAMFraction
是用來控制實際可用的記憶體數量的,比如設定為 1 的話就是 CGroupMemoryLimit
的全部,設定為 2 的話一半,3 的話就是 1/3,以此類推
|MaxRAMFraction取值|堆佔比|容器記憶體=1G|容器記憶體=2G|容器記憶體=4G|容器記憶體=8G|容器記憶體=16G| |:—-:|:—-|:—-:|:—-|:—-:|:—-|:—-:|:—-|:—-:|:—-|:—-:|:—-|:—-:|:—-| |1|≈90%|910.50M|1.78G|3.56G|7.11G|14.22G| |2|≈50%|455.50M|910.50M|1.78G|3.56G|7.11G| |3|≈33%|304.00M|608.00M|1.19G|2.37G|4.74G| |4|≈25%|228.00M|455.50M|910.50M|1.78G|3.56G|
未配置JVM引數
可以看到 Max. Heap Size (Estimated): 3.48G
,未能正確識別 CGroup 資源限制
$ docker run --rm -m 2GB openjdk:8u131-alpine java -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 3.48G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (IcedTea 3.4.0) (Alpine 8.131.11-r2)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
配置JVM引數
配置 -XX:+UnlockExperimentalVMOptions
、-XX:+UseCGroupMemoryLimitForHeap
和 -XX:MaxRAMFraction=1
後即可達到我們想要的結果
$ docker run --rm -m 2GB openjdk:8u131-alpine java -XshowSettings:vm -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -version
VM settings:
Max. Heap Size (Estimated): 1.78G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (IcedTea 3.4.0) (Alpine 8.131.11-r2)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
8u191 及以上版本
從 8u191 開始引入了 java10+ 上的 UseContainerSupport
選項,而且是預設啟用的,不用設定。同時 UseCGroupMemoryLimitForHeap
這個就棄用了,不建議繼續使用,同時還可以通過 -XX:InitialRAMPercentage
、-XX:MaxRAMPercentage
、-XX:MinRAMPercentage
這些引數更加細膩的控制 JVM 使用的記憶體比率。比如一些 Java 程式在執行時會呼叫外部程式、申請 Native Memory 等,所以即使是在容器中執行 Java 程式,也得預留一些記憶體給系統的。所以 -XX:MaxRAMPercentage
不能配置得太大。
未配置JVM引數
可以看到未新增任何 JVM 引數即可正確識別到 CGroup 資源限制
$ docker run --rm -m 2GB openjdk:8u191-alpine java -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 455.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)
配置JVM引數
- 使用
-XX:MaxRAMFraction
引數調整Max. Heap Size
大小`
console $ docker run –rm -m 2GB openjdk:8u191-alpine java -XX:MaxRAMFraction=1 -XshowSettings:vm -version
VM settings: Max. Heap Size (Estimated): 1.78G 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)
* 使用 `-XX:InitialRAMPercentage`、`-XX:MaxRAMPercentage`、`-XX:MinRAMPercentage` 引數更加細膩的控制 JVM 使用的記憶體比率
```console
$ docker run --rm -m 2GB openjdk:8u191-alpine java -XX:InitialRAMPercentage=40.0 -XX:MaxRAMPercentage=90.0 -XX:MinRAMPercentage=50.0 -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 1.60G
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)
參考資料
- http://www.51gjie.com/java/55...
- https://zhuanlan.zhihu.com/p/...
- https://my.oschina.net/neverf...
- https://sevenyu.top/2019/04/0...
- https://qingmu.io/2018/12/17/...
本文由豬齒魚技術團隊原創,轉載請註明出處:豬齒魚官網
關於豬齒魚
豬齒魚Choerodon全場景效能平臺,提供體系化方法論和協作、測試、DevOps及容器工具,幫助企業拉通需求、設計、開發、部署、測試和運營流程,一站式提高管理效率和質量。從團隊協同到DevOps工具鏈、從平臺工具到體系化方法論,豬齒魚全面滿足協同管理與工程效率需求,貫穿端到端全流程,助力團隊效能更快更強更穩定。戳此處試用豬齒魚