JVM 如何获取当前容器的资源限制?

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 翻了下代码,发现最新版本的 java 是能感知容器的资源限制的,就按照jdk版本再翻了下代码。

作者:卜比


最近同事说到 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 或更新版本就完事了。


点击此处查看微服务引擎产品

相关文章
|
1月前
|
Serverless API 容器
函数计算容器模式如何设置多久释放资源啊?
函数计算容器模式如何设置多久释放资源啊?
385 0
|
8月前
|
Cloud Native Linux 虚拟化
【云原生】Docker容器资源限制(CPU/内存/磁盘)
【云原生】Docker容器资源限制(CPU/内存/磁盘)
1142 0
|
2天前
|
Kubernetes 安全 测试技术
超大规模商用 K8s 场景下,阿里巴巴如何动态解决容器资源的按需分配问题?
超大规模商用 K8s 场景下,阿里巴巴如何动态解决容器资源的按需分配问题?
|
1月前
|
存储 安全 数据中心
【Docker 专栏】Docker 容器与宿主机的资源隔离机制
【5月更文挑战第8天】Docker容器利用Namespace和Cgroups实现资源隔离,保证CPU、内存、网络和存储的独立,提升资源利用率和系统安全性。资源隔离有助于简化应用部署与管理,但也带来资源竞争、监控管理及安全挑战。理解并善用资源隔离机制能实现更高效、安全的容器运行。随着技术进步,Docker容器资源隔离将持续优化。
【Docker 专栏】Docker 容器与宿主机的资源隔离机制
|
1月前
|
运维 Linux Docker
Docker详解(十一)——Docker容器CPU资源限额实战Docker详解
Docker详解(十一)——Docker容器CPU资源限额实战
58 5
|
1月前
|
存储 运维 Linux
Docker详解(十)——Docker容器CPU资源限额配置
Docker详解(十)——Docker容器CPU资源限额配置
73 3
|
1月前
|
Kubernetes 调度 容器
Kubernetes容器资源限制
Kubernetes容器资源限制
32 0
|
8月前
|
弹性计算 Kubernetes 调度
《Docker资源限制和调度策略:性能优化与资源管理,打造高效稳定的容器环境》
《Docker资源限制和调度策略:性能优化与资源管理,打造高效稳定的容器环境》
197 0
|
1月前
|
Kubernetes Linux 调度
「译文」深入了解 Kubernetes 指标 - 第三部分 - 容器资源指标
「译文」深入了解 Kubernetes 指标 - 第三部分 - 容器资源指标
|
6天前
|
存储 Java C++
Java虚拟机(JVM)在执行Java程序时,会将其管理的内存划分为几个不同的区域
【6月更文挑战第24天】Java JVM管理内存分7区:程序计数器记录线程执行位置;虚拟机栈处理方法调用,每个线程有独立栈;本地方法栈服务native方法;Java堆存储所有对象实例,垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息;运行时常量池存储常量;直接内存不属于JVM规范,通过`java.nio`手动管理,不受GC直接影响。
16 5