gpt4 book ai didi

java - 容器中的JVM错误地计算处理器?

转载 作者:行者123 更新时间:2023-12-01 13:20:30 24 4
gpt4 key购买 nike

我最近再次进行了一些研究,并偶然发现了这一点。在向 OpenJDK 团队提示之前,我想看看其他人是否观察到了这一点,或者不同意我的结论。

因此,众所周知,JVM 长期以来一直忽略应用于 cgroup 的内存限制。众所周知,它现在将它们考虑在内,从 Java 8 开始更新某些内容,以及 9 和更高版本。不幸的是,基于 cgroup 限制所做的计算是如此无用,以至于您仍然必须手动完成所有工作。请参阅谷歌和数百篇关于此的文章。

我几天前才发现的,并且没有在这些文章中阅读任何一篇文章,是 JVM 如何检查 cgroup 中的处理器数量。处理器计数用于决定用于各种任务的线程数,包括垃圾收集。所以正确理解很重要。

在 cgroup 中(据我所知,我不是专家)您可以设置可用 CPU 时间的限制(--cpus Docker 参数)。这仅限制时间,而不限制并行性。还有 cpu 份额(--cpu-shares Docker 参数),这是在负载下分配 cpu 时间的相对权重。 Docker 将默认值设置为 1024,但这纯粹是一个相对比例。

最后,还有 cpu 集(--cpuset-cpus 用于 Docker)将 cgroup 和 Docker 容器显式分配给处理器的子集。这与其他参数无关,实际上会影响并行性。

因此,在检查我的容器可以并行运行多少线程时,据我所知,只有 cpu 集是相关的。 JVM 虽然忽略了这一点,而是使用 cpu 限制(如果设置),否则 cpu 共享(假设 1024 默认为绝对比例)。恕我直言,这已经很错误了。它计算可用的 CPU 时间来调整线程池的大小。

在 Kubernetes 中情况变得更糟。 AFAIK 最佳实践是不设置 cpu 限制,以便集群节点具有高利用率。此外,您应该为大多数应用程序设置一个低 CPU 请求,因为它们大部分时间都处于空闲状态,并且您希望在一个节点上安排多个应用程序。 Kubernetes 将请求以毫 cpu 为单位设置为 cpu 份额,最有可能在 1000m 以下。 JVM 始终假设一个处理器,即使您的节点运行在某个 64 核 CPU 怪物上。

有没有人也观察过这一点?我在这里错过了什么吗?还是 JVM 开发人员在为 cpu 实现 cgroup 限制时实际上使事情变得更糟?

以供引用:

  • https://bugs.openjdk.java.net/browse/JDK-8146115
  • https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#how-pods-with-resource-limits-are-run
  • cat /sys/fs/cgroups/cpu/cpu.share在容器内,本地或您选择的集群中,获取启动时使用的设置
  • 最佳答案

    作为大型服务(>15K 容器在自己的云中运行分布式 Java 应用程序)的开发者,我也承认所谓的“Java 容器支持”还远非完美。同时,我可以理解实现当前资源检测算法的JVM开发人员的推理。

    问题是,运行容器化应用程序的云环境和用例太多,几乎不可能解决各种配置问题。对于 Kubernetes 中的大多数应用程序,您声称的“最佳实践”不一定适用于其他部署。例如。这绝对不是我们服务的常见情况,大多数容器需要一定的最低保证 CPU 资源量,因此也有一个不能超过的配额,以保证其他容器的 CPU。此策略适用于低延迟任务。 OTOH,您所描述的策略,更适合高吞吐量或批处理任务。

    HotSpot JVM 中当前实现的目标是开箱即用地支持流行的云环境,并提供覆盖默认值的机制。

    有一个email thread Bob Vandette 解释了当前的选择。还有一个comment在源代码中,描述了 JVM 为何查看 cpu.shares并将其除以 1024。

    /*
    * PER_CPU_SHARES has been set to 1024 because CPU shares' quota
    * is commonly used in cloud frameworks like Kubernetes[1],
    * AWS[2] and Mesos[3] in a similar way. They spawn containers with
    * --cpu-shares option values scaled by PER_CPU_SHARES. Thus, we do
    * the inverse for determining the number of possible available
    * CPUs to the JVM inside a container. See JDK-8216366.
    *
    * [1] https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu
    * In particular:
    * When using Docker:
    * The spec.containers[].resources.requests.cpu is converted to its core value, which is potentially
    * fractional, and multiplied by 1024. The greater of this number or 2 is used as the value of the
    * --cpu-shares flag in the docker run command.
    * [2] https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html
    * [3] https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/docker/docker.cpp#L648
    * https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/slave/containerizer/mesos/isolators/cgroups/constants.hpp#L30
    */

    至于并行性,我也第二个 HotSpot 开发者认为 JVM 应该采用 cpu.quotacpu.shares在估计可用 CPU 的数量时考虑在内。当容器分配了一定数量的 vcore 时(以任何一种方式),它只能依赖于这个数量的资源,因为不能保证有更多的资源可供进程使用。考虑一个在 64 核机器上运行的具有 4 个 vcore 的容器。在 64 个并行线程中运行的任何 CPU 密集型任务(GC 就是此类任务的一个示例)将很快耗尽配额,并且操作系统将长时间限制容器。例如。 100 毫秒中的每 94 毫秒,应用程序都会处于停顿状态,因为记帐配额 ( cpu.cfs_period_us) 的默认周期是 100 毫秒。

    无论如何,如果该算法在您的特定情况下无法正常工作,则始终可以使用 -XX:ActiveProcessorCount 覆盖可用处理器的数量。选项,或使用 -XX:-UseContainerSupport 完全禁用容器感知.

    关于java - 容器中的JVM错误地计算处理器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59661653/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com