前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM 如何获取当前容器的资源限制?

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

作者头像
用户1107783
发布2024-04-11 15:07:04
920
发布2024-04-11 15:07:04
举报
文章被收录于专栏:云原生运维社区

最近同事说到Java的 ParallelGCThreads[1] 参数,我翻了下 jdk8 的代码,发现 ParallelGCThreads 的参数默认值如下:

  • 如果 CPU 核心数目少于等于 8,则 GC 线程数量和CPU数一致
  • 如果 CPU 核心数大于 8,则前 8 个核,每个核心对应一个 GC 线;其他核,每 8 个核对应 5 个 GC 线程

但是被提醒,发现即使在分配 4 核的容器上,GC 线程数也为 38。然后就想到应该和容器的资源限制有关——jvm 可能无法觉察到当前容器的资源限制。

翻了下代码,发现最新版本的 Java 是能感知容器的资源限制的,就按照 jdk 版本再翻了下代码:

线上的 jdk(jdk8u144)

Cloud Native

写一个 sleep 1000s 的程序,用于查看 JVM 的线程数量:

代码语言:javascript
复制
./jdk1.8.0_144/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main

然后查看 GC 线程数目:

代码语言:javascript
复制
$ jstack $pid | grep 'Parallel GC Threads' | wc -l
38

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

然后使用 +PrintFlagsFinal 看下参数:

代码语言:javascript
复制
$ ./jdk1.8.0_144/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreads
uintx ParallelGCThreads          =38                     {product}

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

jdk 8u191

Cloud Native

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

运行同样的程序:

代码语言:javascript
复制


./jre1.8.0_191/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main

$ jstack $pid | grep 'Parallel GC Threads' | wc -l
4

查看实际参数:

代码语言:javascript
复制
$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreads
uintx ParallelGCThreads         =4                   {product}

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

代码语言:javascript
复制
$ ./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 数目都是对的了。

如何获取容器资源配额呢?

Cloud Native

结合这个日志和代码,我们也可以看到如何获取容器配额:

首先从 /proc/self/mounts 中读取对应的资源的 mount 位置,比如 CPU 就是在 /sys/fs/cgroup/cpu,cpuacct

代码语言:javascript
复制
$ 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

对于内存:

代码语言:javascript
复制
$ cat /sys/fs/cgroup/memory/memory.limit_in_bytes
10737418240

对于 CPU 资源:

其一,可以通过 quota/period 来算:

代码语言:javascript
复制


$ 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 来获取:

代码语言:javascript
复制
$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.shares
681

不过这个值是 CPU 占用份额,无法根据这个算出来可用 CPU 数量,所以基本没用…

总结

Cloud Native

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生运维圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档