jdk7升jdk8 jvm_JDK 10中更好的容器化JVM

jdk7升jdk8 jvm

TL; DR JDK团队致力于使Java在容器世界中成为良好的公民。 JDK10包含一些更改,以使JVM和您的应用遵守容器限制。 JDK10将于2018年3月发布。

这篇文章是JörgSchad最近发表的文章的反面或后续文章, 没人将Java放在容器中 。 我绝对建议阅读该书,以获取有关容器技术如何影响当今JVM(即JDK9)的出色总结。

但是,我真的不同意他的头衔-很多人确实将JVM工作负载放在了容器中(破坏者:我在最近的几个项目中都这样做过-我们甚至在Fn Project中 对此进行了调整 )。 正如Jörg指出的那样,当JDK10发行时,支持会更好。

JDK10中有大量工作要支持容器化的JVM。 在本文中,我将展示JDK的下一版本将如何感知容器。

我将使用Docker运行最新版本的JDK10(当前为10 + 39)。 要下载JDK,请访问http://jdk.java.net/10/ 。 这些补丁降落在10 + 34。 我正在使用这个Dockerfile 。 我将在Oracle Cloud Infrastructure上使用一个裸机实例,该实例具有72个内核和256Gb RAM。 只是那种担心如何最好地同时运行很多东西的地方😉

CPU管理

许多现有代码使用Runtime.getRuntime().availableProcessors()来调整线程池的大小,例如:

这是明智的策略。 即使您的代码没有直接这样做,您也很可能会使用在后台使用ForkJoinPool的东西, 哦,瞧!

无需指定任何约束,容器化进程将能够查看和使用主机上的所有硬件。 如果这不是您想要的,那么有几种方法可以限制容器可以在Docker中使用的CPU,自然地,您希望JVM应用程序使用适当数量的资源。 在Fn上进行的实验中,我们发现由于线程池的开销过大,创建大量容器化JVM的速度比引导相同数量的虚拟机监控程序VM的速度慢。 然后,您必须关注大量线程之间的争用。

让我们看看availableProcessors的值如何受到不同的CPU节流机制的影响:

主机操作系统

运行在任何容器之外,这是主机的JVM视图。

$ echo 'Runtime.getRuntime().availableProcessors()' | jdk-10/bin/jshell -q
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 72

CPU份额

—cpu-shares [ Doc ]指定。

这将根据您选择的比例对CPU进行配给,但是仅在系统繁忙时才进行配给。 例如,您可以拥有三个共享为1024/512/512的容器,但是这些限制仅在必要时应用。 当有足够的空间时,您的容器化进程可能会使用剩余的CPU时间。

$ echo 'Runtime.getRuntime().availableProcessors()' | docker run --cpu-shares 36864 -i jdk10
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 36

笔记:

  1. 这基于关系1 CPU = 1024个“份额”。 36864 = 36×1024
  2. 也就是说,1024是默认设置,因此在此处指定1024将导致JVM报告72个处理器而不是1个。这似乎是一个等待的陷阱。
  3. 对于JVM或尝试进行这种自省的任何容器化进程,CPU份额很难。 您指定的arg相对于系统上的所有其他容器进行解释。

CPU周期/配额

指定为—cpus (或—cpu-period—cpu-quota ,其中CPUs = quota/period )[ Doc ]。

这使用Linux完全公平调度程序来限制容器的CPU使用率。 这意味着即使机器负载很轻,容器的CPU时间也将有限,并且您的工作量可能会分散在主机上的所有CPU上。 例如,此处的示例可能会为您提供所有72个内核的50%的时间。

$ echo 'Runtime.getRuntime().availableProcessors()' | docker run --cpus 36 -i jdk10
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 36

CPU组

—cpuset-cpus [ Doc ]指定。

与前两个约束不同,这将容器化进程固定到特定的CPU。 您的进程可能必须共享这些CPU,但是显然不允许在任何其他CPU上使用备用容量。

$ echo 'Runtime.getRuntime().availableProcessors()' | docker run --cpuset-cpus 0-35 -i jdk10
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 36

组合方式

您也可以将这些选项混合在一起-例如,在核心0到8上有50%的时间。Docker充分记录了这一点,它将把您链接到内核文档以获取更多信息。

JVM计算

JVM使用的公式是: min(cpuset-cpus, cpu-shares/1024, cpus)舍入到下一个整数。

告诉我使用什么!

当您有足够的内核时,使用CPU集似乎是合乎逻辑的,因为它应该减少上下文切换并增加CPU缓存的一致性。 或者,如果他们花费大量时间来等待中断,则可以有更多线程,在这种情况下, CPU周期/配额可能会很吸引人。 也许您对CPU份额的限制很满意,并且很高兴能够使用备用CPU周期。 像往常一样,最好的建议是做一些分析。 与JavaDoc中的警告相反,我没有看到在单个JVM中availableProcessors随时间改变其结果的任何情况。

记忆

JVM将尝试分配并使其可用的内存量是明确设置的,或者是通过称为Ergonomics的过程为您选择的。 文档指出,在“服务器级”计算机(> 2个处理器,> 2Gb RAM)上,JVM将以“服务器”模式运行,并且最大堆大小将由人体工程学设置为1/4物理内存。 实际上,在64位JVM中,没有其他方法可以替代“服务器”模式。 此外,人体工程学选择的堆大小限制在32Gb左右–如果您想要的更多,则必须使用-Xmx进行请求。

例如,在我的测试服务器(256Gb RAM)上:

$ jdk-10+23/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
   size_t MaxHeapSize                              = 32178700288                              {product} {ergonomic}

32Gb是人体工学的最大值,因为它是可以使用Compressed Oops的最大尺寸。

让我们尝试使用较小的内存限制:

$ docker run -it -m512M  --entrypoint bash jdk10
root@7378a1f0a2a9:/# /java/jdk-10/bin/java  -XX:+PrintFlagsFinal -version | grep MaxHeapSize
   size_t MaxHeapSize                              = 134217728                              {product} {ergonomic}

正如预期的那样,它足够接近128Mb。

$ docker run -it -m512M  jdk10
jshell> Runtime.getRuntime().maxMemory()
$1 ==> 129761280

同样,接近128Mb。 如果我们尝试使用过多的内存,会发生什么也就不足为奇了:

jshell> new byte[140_000_000]
|  java.lang.OutOfMemoryError thrown: Java heap space
|        at (#1:1)

更多人体工程学

人机工程学还可以调整内部JVM值,例如G1GC使用的线程池大小。 这些由arg -XX:+PrintFlagsFinalOTN上描述的ConcGCThreadsParallelGCThreads 。 G1GC线程池大小的选择方法与availableProcessors相同。

主机操作系统

$ jdk-10/bin/java -XX:+PrintFlagsFinal -version | grep -i GCThreads
     uint ConcGCThreads                            = 12                                       {product} {ergonomic}
     uint ParallelGCThreads                        = 48                                       {product} {default}

CPU限制的容器

$ docker run -it --cpus 36  --entrypoint bash jdk10
root@6a94863c54df:/# /java/jdk-10/bin/java -XX:+PrintFlagsFinal -version | grep -i GCThreads
     uint ConcGCThreads                            = 6                                        {product} {ergonomic}
     uint ParallelGCThreads                        = 25                                       {product} {default}

其他值

人体工程学过程还设置了其他一些值:

  • HotSpot编译线程数
  • GC区域大小
  • 代码缓存大小

这是主机与容器值的区别 。 该容器使用--cpus 36 -m 4G运行。

摘要

在JDK10中,将CPU和内存限制应用于容器化JVM似乎很简单。 JVM将正确检测容器的硬件功能,适当调整自身,并很好地表示应用程序的可用容量。

感谢@msgodf和Bob Vandette为这篇文章提供的帮助。

这篇文章最初发表在Matthew Gilliard的博客上

翻译自: https://jaxenter.com/better-containerized-jvms-jdk-10-140593.html

jdk7升jdk8 jvm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值