JVM如何獲取當前容器的資源限制

最近同事說到Java的 ParallelGCThreads 參數,我翻了下jdk8的代碼,發現 ParallelGCThreads 的參數默認值以下:java

  • 若是cpu核心數目少於等於8,則GC線程數量和CPU數一致
  • 若是cpu核心數大於8,則前8個核,每一個核心對應一個GC線;其餘核,每8個核對應5個GC線程

可是被提醒,發現即便在分配4核的容器上,GC線程數也爲38。而後就想到應該和容器的資源限制有關——jvm可能沒法覺察到當前容器的資源限制。node

翻了下代碼,發現最新版本的java是能感知容器的資源限制的,就按照jdk版本再翻了下代碼:bash

線上的jdk(jdk8u144)

寫一個sleep 1000s的程序,而後運行:jvm

./jdk1.8.0_144/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main 
複製代碼

而後查看GC線程數目:ui

$ jstack $pid | grep 'Parallel GC Threads' | wc -l
38
複製代碼

一算就知道物理機器有56個核心(8+(56-8)*5/8=38)spa

而後使用+PrintFlagsFinal看下參數:線程

$ ./jdk1.8.0_144/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreads
uintx ParallelGCThreads          =38                     {product} 
複製代碼

看來jdk8u144並沒有法讀取容器配額。日誌

jdk 8u191

而後發現,從jdk 8u191版本開始,Java就能夠讀取容器配額了:code

運行一樣的程序:內存

./jre1.8.0_191/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main
複製代碼
$ jstack $pid | grep 'Parallel GC Threads' | wc -l
4
複製代碼

查看實際參數:

$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreads
uintx ParallelGCThreads         =4                   {product} 
複製代碼

另外,jdk 8u191引入了PrintContainerInfo參數:

$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintContainerInfo -version
OSContainer::init: Initializing Container Support
Path to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytes
Memory Limit is: 10737418240
Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us
CPU Quota is: 400000
Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us
CPU Period is: 100000
Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares
CPU Shares is: 681
CPU Quota count based on quota/period: 4
CPU Share count based on shares: 1
OSContainer::active_processor_count: 4
Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us
CPU Quota is: 400000
Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us
CPU Period is: 100000
Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares
CPU Shares is: 681
CPU Quota count based on quota/period: 4
CPU Share count based on shares: 1
OSContainer::active_processor_count: 4
……
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
複製代碼

能夠看到,獲取的內存限制、可用CPU數目都是對的了。

如何獲取容器資源配額呢?

結合這個日誌和代碼,咱們也能夠看到如何獲取容器配額:

首先從/proc/self/mounts中讀取對應的資源的mount位置,好比cpu就是在/sys/fs/cgroup/cpu,cpuacct:

$ cat /proc/mounts  | grep -E -w '(cpu|memory)'
cgroup /sys/fs/cgroup/memory cgroup ro,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup ro,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0
複製代碼

對於內存:

$ cat /sys/fs/cgroup/memory/memory.limit_in_bytes
10737418240 
複製代碼

對於cpu資源:

其一,能夠經過quota/period來算:

$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us #單CPU總時間片配額,微秒 
100000
$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us #時間片內,容器可佔用的CPU時間
400000
複製代碼

好比上面就表示分配了4核。

也能夠經過cpu.shares來獲取:

$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.shares
681
複製代碼

不過這個值是cpu佔用份額,沒法根據這個算出來可用cpu數量,因此基本沒用…

相關文章
相關標籤/搜索