作者:卜比

本文是《容器中的 Java》系列文章之 1/n,欢送关注后续连载 :) 。

最近共事说到Java的 ParallelGCThreads [ 1]  参数,我翻了下 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 -l38

一算就晓得物理机器有 56 个外围(8+(56-8)*5/8=38)
而后应用 +PrintFlagsFinal 看下参数:

$ ./jdk1.8.0_144/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreadsuintx ParallelGCThreads          =38                     {product}

看来 jdk8u144 并无奈读取容器配额。

jdk 8u191

而后发现,从 jdk 8u191 [2 ] 版本开始,Java 就能够读取容器配额了:

运行同样的程序:

./jre1.8.0_191/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main$ jstack $pid | grep 'Parallel GC Threads' | wc -l4

查看理论参数:

$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreadsuintx ParallelGCThreads         =4                   {product}

另外,jdk 8u191 引入了 PrintContainerInfo 参数:

$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintContainerInfo -versionOSContainer::init: Initializing Container SupportPath to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytesMemory Limit is: 10737418240Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_usCPU Quota is: 400000Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_usCPU Period is: 100000Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.sharesCPU Shares is: 681CPU Quota count based on quota/period: 4CPU Share count based on shares: 1OSContainer::active_processor_count: 4Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_usCPU Quota is: 400000Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_usCPU Period is: 100000Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.sharesCPU Shares is: 681CPU Quota count based on quota/period: 4CPU Share count based on shares: 1OSContainer::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 0cgroup /sys/fs/cgroup/cpu,cpuacct cgroup ro,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0

对于内存:

$ cat /sys/fs/cgroup/memory/memory.limit_in_bytes10737418240

对于 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.shares681

不过这个值是 CPU 占用份额,无奈依据这个算进去可用 CPU 数量,所以根本没用…

总结

应用 jdk 8u191 或更新版本就完事了。

相干链接

[1] ParallelGCThreads:

https://docs.oracle.com/javas...

[2] jdk 8u191:

https://www.oracle.com/java/t...