在docker容器中运行的JavaJDK8更新131之前的应用程序CPU /内存问题?

问题描述

在docker容器中运行的

JVM(更新131之前的JDK 8)在忽略容器环境设置的CGroup限制。 而且,他们正在查询主机资源,而不是分配给容器的资源。 结果对于JVM来说是灾难性的,即,由于JVM试图分配自己的资源(CPU或内存)超过了CGroup限制所允许的资源,因此docker demon会注意到这一点,并且如果Java程序是使用pid 1运行。

内存问题的解决方案-(可能已在JDK 8更新131中修复) 如上所述,JVM分配给自己的内存比容器允许的更多。这可以通过

轻松解决
  1. 在启动JVM时明确设置最大堆内存限制(使用-Xmx)。 (在131更新之前)
  2. 或通过传递这些标志-(在131更新之后)
    -XX:+UnlockExperimentalVMOptions
    -XX:+UseCGroupMemoryLimitForHeap

解决CPU问题(可能已在JDK更新212中修复) 再次如上所述,在docker中运行的JVM将直接查看主机硬件并获得可用的CPU总数。然后它将尝试根据此CPU数量进行访问或优化。

  1. 在JDK 8更新212之后,在docker容器中运行的所有JVM都将遵守分配给容器的cpu限制,而不直接查看主机cpus。 如果按以下方式启动具有cpu限制的容器,则JVM将遵守此限制并将其自身限制为1 cpu。
    docker run -ti --cpus 1 -m 1G openjdk:8u212-jdk //在此容器中运行的jvm限制为1cpu。
  2. 此处是我的问题: JDK8 Update 212中的CPU问题已得到修复,但是如果我无法更新JVM并且我正在运行131更新之前的版本,该怎么办?我已解决了CPU问题。

解决方法

Linux容器支持首先出现在JDK 10中,然后移植到8u191,请参见JDK-8146115

早期的JVM版本获得了可用的CPU数量,如下所示。

  • 在8u121之前,HotSpot JVM依靠sysconf(_SC_NPROCESSORS_ONLN) libc调用。反过来,glibc读取系统文件/sys/devices/system/cpu/online。因此,为了伪造可用CPU的数量,可以使用bind mount替换此文件:

    echo 0-3 > /tmp/online
    docker run --cpus 4 -v /tmp/online:/sys/devices/system/cpu/online ...
    

    要仅设置一个CPU,请写echo 0而不是echo 0-3

  • 从8u121开始,JVM成为taskset aware。它开始调用sysconf而不是sched_getaffinity来查找该进程的CPU关联掩码。

    这打破了绑定安装技巧。不幸的是,您不能像sched_getaffinity一样伪造sysconf。但是,可以使用LD_PRELOAD替换sched_getaffinity的libc实现。

我写了一个小的共享库proccount,它同时替换了sysconfsched_getaffinity。因此,该库可用于在8u191之前的所有JDK版本中设置正确数量的可用CPU。

工作方式

  1. 首先,它读取cpu.cfs_quota_uscpu.cfs_period_us来查找容器是否使用--cpus选项启动。如果两者都大于零,则CPU数量估计为

    cpu.cfs_quota_us / cpu.cfs_period_us
    
  2. 否则它将读取cpu.shares并估计可用CPU的数量为

    cpu.shares / 1024
    

    这种CPU计算类似于在现代的可感知容器的JDK中的实际计算。

  3. 该库定义(重写)sysconfsched_getaffinity函数以返回在(1)或(2)中获得的处理器数量。

如何编译

gcc -O2 -fPIC -shared -olibproccount.so proccount.c -ldl

使用方法

LD_PRELOAD=/path/to/libproccount.so java <args>

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...