在Docker容器中运行的Java(JDK8更新131之前的版本)应用程序CPU/内存问题? [英] Java (prior to JDK8 update 131) applications running in docker container CPU / Memory issues?

查看:563
本文介绍了在Docker容器中运行的Java(JDK8更新131之前的版本)应用程序CPU/内存问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

JVM's (JDK 8 before Update 131) running in docker containers were ignoring the CGroup limitations set by the container environment. And, they were querying for host resources and not what was allocated to the container. The result is catastrophic for the JVM i.e As the JVM was trying to allocate itself more resources (CPU or Memory) than what is permitted through CGroup limits, docker demon would notice this and kill the JVM process or the container itself if the java program was running with pid 1.

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

Solution for memory issue - (possibly fixed in JDK 8 update 131) Like described above, JVM was allocating it's self more memory than what's allowed for the container. This could be easily fixed by

  1. 在启动JVM时明确设置最大堆内存限制(使用-Xmx). (在131更新之前)
  2. 或通过传递这些标志-(在131更新之后)
    -XX:+UnlockExperimentalVMOptions
    -XX:+UseCGroupMemoryLimitForHeap
  1. explicitly setting the max heap memory limit (using -Xmx ) while starting the JVM. ( prior to 131 update)
  2. or by passing these flags - (after 131 update)
    -XX:+UnlockExperimentalVMOptions and
    -XX:+UseCGroupMemoryLimitForHeap

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

Resolving the CPU issue (possibly fixed in JDK update 212 ) Again like described above, JVM running in docker would look at the host hardware directly and obtain the total CPUs available. Then it would try to access or optimize based on this CPU counts.

  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问题.
  1. After JDK 8 update 212, any JVM running in docker container will respect the cpu limits allocated to container and not look into host cpus directly. If a container with cpu limitation is started as below, JVM will respect this limitation and restrict itself to 1 cpu.
    docker run -ti --cpus 1 -m 1G openjdk:8u212-jdk //jvms running in this container are restricted to 1cpu.
  2. HERE IS MY QUESTION: The CPU issue is probabily fixed in JDK8 Update 212, but what if I can not update my JVM and I am running version prior to update 131 , how can I fix the cpu issue.

推荐答案

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

Linux container support first appeared in JDK 10 and then ported to 8u191, see JDK-8146115.

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

Earlier versions of the JVM obtained the number of available CPUs as following.

  • Prior to 8u121, HotSpot JVM relied on sysconf(_SC_NPROCESSORS_ONLN) libc call. In turn, glibc read the system file /sys/devices/system/cpu/online. Therefore, in order to fake the number of available CPUs, one could replace this file using a 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

To set only one CPU, write echo 0 instead of echo 0-3

从8u121开始,JVM变得任务集可用.它开始调用sched_getaffinity而不是sysconf来查找该进程的CPU亲和力掩码.

Since 8u121 the JVM became taskset aware. Instead of sysconf, it started calling sched_getaffinity to find the CPU affinity mask for the process.

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

This broke bind mount trick. Unfortunately, you can't fake sched_getaffinity the same way as sysconf. However, it is possible to replace libc implementation of sched_getaffinity using LD_PRELOAD.

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

I wrote a small shared library proccount that replaces both sysconf and sched_getaffinity. So, this library can be used to set the right number of available CPUs in all JDK versions before 8u191.

工作方式

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

  1. First, it reads cpu.cfs_quota_us and cpu.cfs_period_us to find if the container is launched with --cpus option. If both are above zero, the number of CPUs is estimated as

cpu.cfs_quota_us / cpu.cfs_period_us

  • 否则它将读取cpu.shares并将可用CPU的数量估计为

  • Otherwise it reads cpu.shares and estimates the number of available CPUs as

    cpu.shares / 1024
    

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

    Such CPU calculation is similar to how it actually works in a modern container-aware JDK.

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

    The library defines (overrides) sysconf and sched_getaffinity functions to return the number of processors obtained in (1) or (2).

    如何编译

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

    使用方法

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

    这篇关于在Docker容器中运行的Java(JDK8更新131之前的版本)应用程序CPU/内存问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆