暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

666

最近同事说到 Java 的ParallelGCThreads 参数,我翻了下 jdk8 的代码,发现  ParallelGCThreads 的参数默认值如下:
  • 如果 cpu 核心数目少于等于 8,则 GC 线程数量和 CPU 数一致
  • 如果 cpu 核心数大于 8,则前 8 个核,每个核心对应一个 GC 线;其他核,每 8 个核对应 5 个 GC 线程

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

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

线上的 jdk(jdk8u144)

Aliware

写一个 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

        Aliware

        然后发现,从 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 数目都是对的了。

              如何获取容器资源配额

              Aliware

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

              首先从 /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 数量,所以基本没用。

                      总结

                      Aliware

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

                      点击阅读原文查看微服务引擎产品

                      文章转载自阿里巴巴中间件,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论