您的位置:网站首页 > Java软件 > 正文

Java和Docker的那些事儿

类别:Java软件 日期:2019-3-11 8:16:29 人气: 来源:

  Java和Docker不是天然的朋友。 Docker可以设置内存和CPU,而Java不能自动检测到。使用Java的Xmx标识(繁琐/重复)或新的实验性JVM标识,我们可以解决这个问题。

  Java和Docker的结合并不是完美匹配的,最初的时候离完美匹配有相当大的距离。对于初学者来说,JVM的全部设想就是,虚拟机可以让程序与底层硬件无关。

  那么,把我们的Java应用打包到JVM中,然后整个再塞进Docker容器中,能给我们带来什么好处呢?大多数情况下,你只是在复制JVMs和Linux容器,除了浪费更多的内存,没任何好处。感觉这样子挺傻的。

  不过,Docker可以把你的程序,设置,特定的JDK,Linux设置和应用服务器,还有其他工具打包在一起,当做一个东西。站在DevOps/Cloud的角度来看,这样一个完整的容器有着更高层次的封装。

  时至今日,绝大多数产品级应用仍然在使用Java 8(或者更旧的版本),而这可能会带来问题。Java 8(update 131之前的版本)跟Docker无法很好地一起工作。问题是在你的机器上,JVM的可用内存和CPU数量并不是Docker允许你使用的可用内存和CPU数量。

  比如,如果你了你的Docker容器只能使用100MB内存,但是呢,旧版本的Java并不能识别这个。Java看不到这个。JVM会要求更多内存,而且远超这个。如果使用太多内存,Docker将采取行动并容器内的进程!JAVA进程被干掉了,很明显,这并不是我们想要的。

  为了解决这个问题,你需要给Java指定一个最大内存。在旧版本的Java(8u131之前),你需要在容器中通过设置-Xmx来堆大小。这感觉不太对,你可不想定义这些两次,也不太想在你的容器中来定义。

  幸运的是我们现在有了更好的方式来解决这个问题。从Java 9之后(8u131+),JVM增加了如下标志:

  这些标志强制JVM检查Linux的cgroup配置,Docker是通过cgroup来实现最大内存设置的。现在,如果你的应用到达了Docker设置的(比如500MB),JVM是可以看到这个的。JVM将会尝试GC操作。如果仍然超过内存,JVM就会做它该做的事情,抛出OutOfMemoryException。也就是说,JVM能够看到Docker的这些设置。

  第二个问题是类似的,但它与CPU有关。简而言之,JVM将查看硬件并检测CPU的数量。它会优化你的runtime以使用这些CPUs。但是同样的情况,这里还有另一个不匹配,Docker可能不允许你使用所有这些CPUs。可惜的是,这在Java 8或Java 9中并没有修复,但是在Java 10中得到了解决。

  从Java 10开始,可用的CPUs的计算将采用以不同的方式(默认情况下)解决此问题(同样是通过UseContainerSupport)。

  作为一个有趣的,让我们验证并测试Docker如何使用几个不同的JVM版本/标志甚至不同的JVM来处理内存不足。

  正如所料,Docker已经了我们的Java进程。不是我们想要的(!)。你也可以看到输出,Java认为它仍然有大量的内存需要分配。

  在提供了我们自己的内存之后,进程正常停止,JVM理解它正在运行的。然而,问题在于你现在将这些内存设置了两次,Docker一次,JVM一次。

  如前所述,随着增加新标志来修复问题,JVM现在可以遵循Docker所提供的设置。我们可以使用版本新一点的JVM来测试它。

  这一次我们没有告诉JVM的是什么,我们只是告诉JVM去检查正确的设置!现在感觉好多了。

  有些人在评论和Reddit上提到Java 10通过使实验标志成为新的默认值来解决所有问题。这种行为可以通过禁用此标志来关闭:-:-UseContainerSupport。

  然而,在这个ngithly构建中有一个问题,导出的PATH指向旧的Java 10+23目录,而不是10+46,我们需要修复这个问题。

  我最近也在试用OpenJ9,这个免费的替代JVM已经从IBM J9开源,现在由Eclipse。

  它运行速度快,内存管理非常好,性能卓越,经常可以为我们的微服务节省多达30-50%的内存。这几乎可以将Spring Boot应用程序定义为’micro’了,其运行时间只有100-200mb,而不是300mb+。我打算尽快就此写一篇关于这方面的文章。

  我真的希望类似的选项将很快添加到OpenJ9中,因为我希望在生产中运行这个选项,而不必指定最大内存两次。 Eclipse/IBM正在努力修复这个问题,已经提了issues,甚至已经针对issues提交了PR。

  在这种情况下,堆大小受限于分配给Docker实例的内存,这适用于较旧的JVM和OpenJ9。这当然是错误的,因为容器本身和堆外的JVM的其他部分也使用内存。但它似乎工作,显然Docker在这种情况下是宽松的。也许某些bash大神会做出更好的版本,从其他进程的字节中减去一部分。

  奇怪的是,这个标志在OpenJ9中默认没有启用,就像它在Java 10中一样。再说一次:确保你测试了这是你想在一个Docker容器中运行Java。

  如果您在Docker容器中运行Java,请确保你设置了Docker内存和在JVM中也做了,或者你的JVM能够理解这些。

  对于OpenJ9(我强烈使用,可以在生产中有效减少内存占用量),现在使用-Xmx设置,但很快会出现一个支持UseContainerSupport标志的版本。带土字旁的男孩名字

  

关键词:java图标
0
0
0
0
0
0
0
0
下一篇:没有资料

网友评论 ()条 查看

姓名: 验证码: 看不清楚,换一个

推荐文章更多

热门图文更多

最新文章更多

关于联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助

郑重声明:本站资源来源网络 如果侵犯了你的利益请联系站长删除

CopyRight 2010-2012 技术支持 FXT All Rights Reserved