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

瓦姆什

在 docker 容器中运行的 JVM(更新 131 之前的 JDK 8)忽略了容器环境设置的 CGroup 限制。而且,他们查询的是主机资源,而不是分配给容器的资源。结果对 JVM 来说是灾难性的,即当 JVM 试图为自己分配比 CGroup 限制所允许的更多的资源(CPU 或内存)时,如果 java 程序是以 pid 1 运行。

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

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

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

  1. 在 JDK 8 更新 212 之后,在 docker 容器中运行的任何 JVM 将遵守分配给容器的 cpu 限制,而不是直接查看主机 cpu。如果一个具有 cpu 限制的容器如下启动,JVM 将尊重这个限制并将自身限制为 1 个 cpu。
    docker run -ti --cpus 1 -m 1G openjdk:8u212-jdk//在这个容器中运行的jvm被限制为1cpu。
  2. 这是我的问题: CPU 问题可能在 JDK8 更新 212 中得到解决,但是如果我无法更新我的 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 的数量,可以使用绑定安装替换此文件

    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 就可以识别任务集了取而代之的是sysconf,它开始调用sched_getaffinity以查找进程的 CPU 关联掩码。

    这打破了绑定安装技巧。不幸的是,你不能sched_getaffinitysysconf. 但是,可以sched_getaffinity使用LD_PRELOAD替换 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>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用Ubuntu容器(ascii,utf-8)在docker(Python,Java,Ruby等)中运行应用程序时的编码问题

Docker容器内部的应用程序更新?

Docker / LXC容器是正在运行的应用程序还是内存中的东西?

在具有内存限制的 Docker 容器中运行 .NET Core 应用程序

更新Docker中现有容器的内存/ CPU限制

如何检查 Docker 容器中的应用程序是否忽略 Java 内存选项?

Java应用程序如何知道它正在Docker容器中运行

如何将 Eureka 服务 ip 传递给在 docker 容器中运行的 java 应用程序?

Marathon无法运行Docker容器中的应用程序

检查React应用程序是否在Docker容器中运行

如何访问在Docker容器中运行的Spring应用程序?

在手臂上的Docker容器中运行C musl应用程序时出现time()问题

在带有 WSL2 的 Windows 10 Docker 桌面中,docker 容器在哪里以及 Linux 容器如何运行 java 应用程序,而不是 windows nanoserver?

IntelliJ Idea:在Docker容器中构建和运行Java应用

如何使用Docker容器在Java程序中运行python脚本?

如何使用Docker容器在Java程序中运行python脚本?

我可以得到哪个版本的openjdk8来构建更新131,与oracle的最新版本相同?jdk8 / jdk8u?

带有Flask应用程序的Docker容器的内存泄漏

在docker swarm中运行的docker容器中的firebase身份验证错误nodejs应用程序

如何同步在Docker容器上运行的Java应用程序的时间?

在Gitlab运行程序中的Docker容器内运行测试命令时出现问题

FastAPI应用程序在本地运行,但不在Docker容器中运行

Spring Boot应用程序可以在IntelliJ中运行,但不能作为Docker容器运行

访问最近部署在Docker容器中的vue应用程序时出现问题

如何更新Docker容器映像但保留容器应用程序生成的文件

未在Docker容器中运行的.NET Core应用程序中创建日志文件

在Docker容器中的Eclipse中运行JavaFX GUI应用程序时发生致命错误

如何在 docker 容器中的 .net 核心应用程序中运行 python 脚本?

将Docker服务容器中的应用程序连接到在外部网络Docker容器上运行的数据库