现在的Java在Docker中有什么问题?
很多应用都运行于JVM,并运行在容器中,一些大型的数据服务都可以在容器中运行,例如 Apache Spark和 Kafka。
随着JVM与容器结合得越来越紧密,问题也暴露了出来,主要是内存和CPU的大小使用问题,根本原因在于Java根本意识不到自己是在容器中运行的。
Java 默认的 heap 是物理内存的 1/4,例如一台机器的内存是 2GB,我们运行一个java容器,容器的内存限制在 512,然后在容器中看一下最大堆大小:
可以看到,heap 为 512M,也就是物理内存的1/4,并不是根据容器内存来的。
这在实际应用是就会产生问题,例如会被管理程序杀掉。
解决方案可以使用在 Dockerfile 中指定环境变量来定义JVM参数来影响堆大小,或者使用使用Fabric8社区提供的基础Docker镜像,虽然有效,但有限,而且不便,而在 Java 10 中,这些问题会被彻底解决。
Java10 的解决方案
(1)容器内存限制
对于上面的示例,下面使用java10再测试一下:
这里就对了,128Mb
(2)设置可用的 CPU
默认情况下,每个容器都可以无限制的使用宿主机的CPU计算周期,但可以进行设置限定,Java 10 可以这样限制:
还可以设置 CPU 的权重占比,但如果一个容器闲置了,其他容器是可以使用剩余的 CPU 时间的
闲置可用的 CPU :
(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 将会正确感知到自己运行于容器,与容器完美融合,我们就不用经常踩坑了。