现在的Java在Docker中有什么问题?

很多应用都运行于JVM,并运行在容器中,一些大型的数据服务都可以在容器中运行,例如 Apache SparkKafka

随着JVM与容器结合得越来越紧密,问题也暴露了出来,主要是内存和CPU的大小使用问题,根本原因在于Java根本意识不到自己是在容器中运行的

Java 默认的 heap 是物理内存的 1/4,例如一台机器的内存是 2GB,我们运行一个java容器,容器的内存限制在 512,然后在容器中看一下最大堆大小:

Java10 将可以优雅的整合 Docker_java

可以看到,heap 为 512M,也就是物理内存的1/4,并不是根据容器内存来的。

这在实际应用是就会产生问题,例如会被管理程序杀掉。

解决方案可以使用在 Dockerfile 中指定环境变量来定义JVM参数来影响堆大小,或者使用使用Fabric8社区提供的基础Docker镜像,虽然有效,但有限,而且不便,而在 Java 10 中,这些问题会被彻底解决。

Java10 的解决方案

(1)容器内存限制

对于上面的示例,下面使用java10再测试一下:

Java10 将可以优雅的整合 Docker_java_02


这里就对了,128Mb

(2)设置可用的 CPU

默认情况下,每个容器都可以无限制的使用宿主机的CPU计算周期,但可以进行设置限定,Java 10 可以这样限制:

Java10 将可以优雅的整合 Docker_java_03

还可以设置 CPU 的权重占比,但如果一个容器闲置了,其他容器是可以使用剩余的 CPU 时间的

Java10 将可以优雅的整合 Docker_java_04

闲置可用的 CPU :

Java10 将可以优雅的整合 Docker_java_05

(3)估算需要分配的内存和CPU

由于容器的资源用量可以设置了,那么就可以估算出实际需要分配的CPU和内存总量。

例如,有一个应用分布部署在10个节点上,其中的5个节点每个需要 512Mb 的内存、1024 CPU(一个CPU的共享占比用1024来表达),另5个节点每个需要 256Mb 内存和 512 CPU。

对于内存,这个应用便最小需要 5Gb

512Mb x 5 = 2.56 Gb

256Mb x 5 = 1.28 Gb

需要 8 CPUs 才能运行良好

1024 x 5 = 5 CPUs

512 x 5 = 3 CPUs

小结

Java 10 将会正确感知到自己运行于容器,与容器完美融合,我们就不用经常踩坑了。