作者:卜比
最近搭档说到 Java 的ParallelGCThreads参数,我翻了下 jdk8 的代码,发现 ParallelGCThreads 的参数默认值如下:
- 如果 cpu 中心数目少于等于 8,则 GC 线程数量和 CPU 数一致
- 如果 cpu 中心数大于 8,则前 8 个核,每个中心对应一个 GC 线;其他核,每 8 个核对应 5 个 GC 线程
但是被提示,发现即便在分配 4 核的容器上,GC 线程数也为 38。然后就想到应该和容器的资源约束有关—— jvm 可能无法觉察到当时容器的资源约束。
翻了下代码,发现最新版本的 java 是能感知容器的资源约束的,就按照jdk版本再翻了下代码。
线上的 jdk(jdk8u144)
写一个 sleep 1000s 的程序,用于检查 JVM 的线程数量:
./jdk1.8.0_144/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main
然后检查 GC 线程数目:
$ jstack $pid | grep 'Parallel GC Threads' | wc -l
38
一算就知道物理机器有 56 个中心(8+(56-8)*5/8=38)
然后运用 +PrintFlagsFinal 看下参数:
$ ./jdk1.8.0_144/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | grep ParallelGCThreads
uintx ParallelGCThreads =38 {product}
看来 jdk8u144 并无法读取容器配额。
jdk 8u191
然后发现,从jdk 8u191 版本开端,Java 就能够读取容器配额了。运转相同的程序:
./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 数量,所以基本没用。
总结
运用 jdk 8u191 或更新版本就完事了。
点击此处检查微服务引擎产品