Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 防止Docker容器CPU重置?_Java_Spring_Docker_Tomcat - Fatal编程技术网

Java 防止Docker容器CPU重置?

Java 防止Docker容器CPU重置?,java,spring,docker,tomcat,Java,Spring,Docker,Tomcat,这是一个棘手的问题,有点难以解释,但我会尝试一下,看看是否有人有类似的问题+修复 快速背景: 在Docker容器中的Tomcat上运行大型JavaSpring应用程序。其他容器很简单,一个用于JMS队列,另一个用于Mysql。我在Windows上运行,给了Docker和我一样多的CPU(还有内存)。我已经在docker compose中为Catalina设置了JAVA_选项以最大化内存和内存限制,但问题似乎与CPU有关 当应用程序处于空闲状态时,它通常占用103%的CPU(8核,最多800%)。

这是一个棘手的问题,有点难以解释,但我会尝试一下,看看是否有人有类似的问题+修复

快速背景:
在Docker容器中的Tomcat上运行大型JavaSpring应用程序。其他容器很简单,一个用于JMS队列,另一个用于Mysql。我在Windows上运行,给了Docker和我一样多的CPU(还有内存)。我已经在docker compose中为Catalina设置了JAVA_选项以最大化内存和内存限制,但问题似乎与CPU有关

当应用程序处于空闲状态时,它通常占用103%的CPU(8核,最多800%)。我们使用一个进程(使用一个线程池)运行一些工作人员,以执行一些代码。在我的本地主机上(中间没有docker),它跑得很快,飞得很快,很快就吐出原木

问题: 在Docker中运行时,观察
Docker stats-a
我可以看到当这个过程开始时CPU开始加速。同时,在日志中,随着CPU的不断增长,一切都像预期的那样飞速发展。它似乎接近700%,然后它有点死了,但它没有。当它达到这个阈值时,我看到CPU急剧下降到<5%,并停留一段时间。此时日志停止打印,所以我假设什么都没有发生。最终,它会反弹回来,回到约120%,并继续它的过程,就像什么都没发生一样,有时会反弹到约400%

我正在尝试的

我在内存设置方面做得不成功,但这更像是CPU问题。我知道Docker中的Java有点不稳定,但我已经在我的健壮的开发盒上给了它所有的空间,在这里,这个过程可以在本地顺利运行。我发现CPU尖峰会消失很奇怪,但容器本身不会消失或重置。有没有人见过类似的问题,或者知道用Docker进一步解决CPU问题的方法


谢谢。

JVM容器中的资源分配有一个问题,它指的是整个系统矩阵,而不是容器矩阵。在Java7和Java8中,JVM工效学应用了系统(实例)矩阵,例如内核和内存的数量,而不是docker分配的资源(内核和内存)。因此,JVM根据核心计数和内存初始化了许多参数,如下所示

JVM内存占用

-Perm/元空间

-JIT字节码

-堆大小(实例内存的1/4)

中央处理器

-没有。JIT编译器线程

-没有。垃圾收集线程

-否。公用分叉联接池中的线程

因此,容器往往会由于高CPU而变得无响应,或者通过OOM终止容器。原因是JVM忽略了容器CGGroups和名称空间,以限制内存和CPU周期。因此,JVM倾向于获得更多的实例资源,而不是限制docker分配的资源的单独分配

范例

假设两个容器在4核实例上运行,内存为8GB。当谈到docker初始化点时,假设docker具有1GB内存和2048个CPU周期作为硬限制。在这里,每个容器看到4个内核,这些JVM根据它们的状态分别分配内存、JIT编译器和GC线程。但是,JVM将看到该实例上的内核总数(4),并使用该值初始化我们前面看到的默认线程数。因此,两个容器的JVM矩阵如下所述

-4*2个Jit编译器线程

-4*2个垃圾收集线程

-2 GB堆大小*2(实例完整内存的¼,而不是docker分配的内存)

就记忆而言

根据上面的示例,JVM将逐渐增加堆的使用率,因为JVM看到2GB堆的最大大小,即实例内存(8GB)的四分之一。一旦容器的内存使用达到1GB的硬限制,该容器将被OOM kill终止

在CPU方面

根据上面的示例,一个JVM已经用4个垃圾收集线程和4个JIT编译器初始化。然而,docker只分配2048个CPU周期。因此,它会导致高CPU、更多上下文切换和容器无响应,最终会因高CPU而终止容器

解决方案 基本上,有两个进程,即CGGroups和Namespaces,它们在操作系统级别处理这种情况。但是,JAVA 7和8不接受CGgroup和名称空间,但是jdk_1.8.131之后的版本能够通过JVM参数(-XX:+UseCGroupMemoryLimitForHeap,-XX:+UnlockExperimentalVMOptions)启用CGgroup限制。然而,它只为内存问题提供解决方案,而不关心CPU集问题

使用OpenJDK9,JVM将自动检测CPUsets。特别是在编排中,它还能够使用JVM标志(XX:ParallelGCThreads,XX:ConcGCThreads)根据容器上的CPU周期计数手动覆盖CPU集线程计数的默认参数