jdk11新特性——完全支持Linux容器(包括Docker)

Posted 小志的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk11新特性——完全支持Linux容器(包括Docker)相关的知识,希望对你有一定的参考价值。

目录

一、问题

  • 许多运行在Java虚拟机中的应用程序(包括Apache Spark和Kafka等数据服务以及传统的企业应用程序)都可以在Docker容器中运行。但是在Docker容器中运行Java应用程序一直存在一个问题,那就是在容器中运行JVM程序在设置内存大小和CPU使用率后,会导致应用程序的性能下降。这是因为Java应用程序没有意识到它正在容器中运行。

二、问题的解决

  • 随着Java 10的发布,这个问题总算得以解决,JVM现在可以识别由容器控制组(cgroups)设置的约束。可以在容器中使用内存和CPU约束来直接管理Java应用程序,其中包括:
    (1)、遵守容器中设置的内存限制
    (2)、在容器中设置可用的CPU
    (3)、在容器中设置CPU约束
    (4)、Java 10的这个改进在Docker for Mac、Docker for Windows以及Docker Enterprise Edition等环境均有效。

三、容器的内存限制

  • 在Java 9之前,JVM无法识别容器使用标志设置的内存限制和CPU限制。而在Java 10中,内存限制会自动被识别并强制执行。

  • Java将服务器类机定义为具有2个CPU和2GB内存,以及默认堆大小为物理内存的1/4。例如,Docker企业版安装设置为2GB内存和4个CPU的环境,我们可以比较在这个Docker容器上运行Java 8和Java 10的区别。

  • 对于Java 8:最大堆大小为512M或Docker EE安装设置的2GB的1/4,而不是容器上设置的512M限制。

    docker container run -it -m512 --entrypoint bash openjdk:latest
    $ docker-java-home/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
    uintx MaxHeapSize                              := 524288000                          product
    openjdk version "1.8.0_162"
    1
    2
    3
    4
    
  • 对于Java 10:在Java 10上运行相同的命令表明,容器中设置的内存限制与预期的128M非常接近。

    docker container run -it -m512M --entrypoint bash openjdk:10-jdk
    $ docker-java-home/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
    size_t MaxHeapSize                              = 134217728                          product ergonomic
    openjdk version "10" 2018-03-20
    1
    2
    3
    4
    

四、设置可用的CPU

  • 默认情况下,每个容器对主机CPU周期的访问是无限的。可以设置各种约束来限制给定容器对主机CPU周期的访问。Java 10可以识别这些限制:

    docker container run -it --cpus 2 openjdk:10-jdk
    jshell> Runtime.getRuntime().availableProcessors()
    $1 ==> 2
    
  • 分配给Docker EE的所有CPU会获得相同比例的CPU周期。这个比例可以通过修改容器的CPU share权重来调整,而CPU share权重与其它所有运行在容器中的权重相关。此比例仅适用于正在运行的CPU密集型的进程。当某个容器中的任务空闲时,其他容器可以使用余下的CPU时间。实际的CPU时间的数量取决于系统上运行的容器的数量。这些可以在Java 10中设置:

    docker container run -it --cpu-shares 2048 openjdk:10-jdk
    jshell> Runtime.getRuntime().availableProcessors()
    $1 ==> 2
    1
    2
    3
    
  • cpu设置约束设置了哪些CPU允许在Java 10中执行。

    docker run -it --cpuset-cpus="1,2,3" openjdk:10-jdk
    jshell> Runtime.getRuntime().availableProcessors()
    $1 ==> 3
    1
    2
    3
    

五、分配内存和CPU

  • 使用Java 10,可以使用容器设置来估算部署应用程序所需的内存和CPU的分配。我们假设已经确定了容器中运行的每个进程的内存堆和CPU需求,并设置了JAVA_OPTS配置。例如,如果有一个跨10个节点分布的应用程序,其中五个节点每个需要512Mb的内存和1024个CPU-shares,另外五个节点每个需要256Mb和512个CPU-shares。

  • 1个CPU share比例由1024表示。

  • 对于内存,应用程序至少需要分配5Gb。

    512Mb × 5 = 2.56Gb
    256Mb × 5 = 1.28Gb
    
  • 该应用程序需要8个CPU才能高效运行。

    1024 x 5 = 5CPU
    512 x 5 = 3CPU
    
  • 最佳实践是建议分析应用程序以确定运行在JVM中的每个进程实际需要多少内存和分配多少CPU。但是,Java 10消除了这种猜测,可以通过调整容器大小以防止Java应用程序出现内存不足的错误以及分配足够的CPU来处理工作负载。

以上是关于jdk11新特性——完全支持Linux容器(包括Docker)的主要内容,如果未能解决你的问题,请参考以下文章

jdk11新特性——支持G1上的并行完全垃圾收集

jdk11新特性——支持G1上的并行完全垃圾收集

Java12新特性 -- 其他新增,移除,废弃项

spring 5 新特性

jdk11新特性——官方的更新列表

jdk11新特性——官方的更新列表