在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    Java 服務(wù) Docker 容器化最佳實踐

    一、概述

    當(dāng)我們在容器中運行 Java 應(yīng)用程序時,可能希望對其進行調(diào)整參數(shù)以充分利用資源。

    在本教程中,我們將了解如何在運行 Java 進程的容器中設(shè)置 JVM 參數(shù)。本文將重點關(guān)注常見的 -Xmx 和-Xms 標志。

    另外,我們還將研究使用某些 Java 版本運行的程序容器化的常見問題,以及如何在常見的容器化 Java 應(yīng)用程序時設(shè)置自定義標志。

    二、Java 容器中的默認堆設(shè)置

    過去,JVM 不知道分配給容器的內(nèi)存和 CPU。

    Java 10 引入了一個新設(shè)置:+UseContainerSupport(默認啟用)來修復(fù) 這個問題[3],并在 8u191[4] 中將修復(fù)反向移植到 Java 8 。

    現(xiàn)在 JVM 可以根據(jù)分配給容器的內(nèi)存計算其內(nèi)存。

    1. 自動內(nèi)存計算

    當(dāng)不設(shè)置-Xmx和-Xmx參數(shù)時,JVM 會根據(jù)系統(tǒng)規(guī)格來調(diào)整堆大小

    看看堆大?。?/p>

    $ java -XX:+PrintFlagsFinal -version | grep -Ei “maxheapsize|maxram”

    輸出結(jié)果如下:

    openjdk version “15” 2020-09-15OpenJDK Runtime Environment AdoptOpenJDK (build 15+36)OpenJDK 64-Bit Server VM AdoptOpenJDK (build 15+36, mixed mode, sharing) size_t MaxHeapSize = 4253024256 {product} {ergonomic} uint64_t MaxRAM = 137438953472 {pd product} {default} uintx MaxRAMFraction = 4 {product} {default} double MaxRAMPercentage = 25.000000 {product} {default} size_t SoftMaxHeapSize = 4253024256 {manageable} {ergonomic}

    我們看到 JVM 將其堆大小設(shè)置為可用 RAM 的大約 25%。在這個例子中,在一個 16GB 的系統(tǒng)上分配了 4GB。

    出于測試目的,創(chuàng)建一個文件,名為PrintXmxXms.java,內(nèi)容是以 MB 為單位打印堆大小,代碼內(nèi)容如下:

    import java.lang.management.ManagementFactory;import java.lang.management.MemoryMXBean;public class PrintXmxXms { public static void main(String[] args) { int mb = 1024 * 1024; MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); long xmx = memoryBean.getHeapMemoryUsage().getMax() / mb; long xms = memoryBean.getHeapMemoryUsage().getInit() / mb; System.out.println(“Initial Memory (xms) : ” + xms + “mb”); System.out.println(“Max Memory (xmx) : ” + xmx + “mb”); }}

    假設(shè)已經(jīng)安裝了 JDK,可以編譯程序并運行:

    $ javac ./PrintXmxXms.java$ java -cp . PrintXmxXms

    在 16Gb RAM 的主機上,輸出結(jié)果為:

    INFO: Initial Memory (xms) : 254mbINFO: Max Memory (xmx) : 4056mb

    下面,在容器中嘗試一下。

  • JDK 8u191 之前的版本在包含 PrintXmxXms.java 文件的文件夾中添加以下 Dockerfile:
  • FROM openjdk:8u92-jdk-alpineCOPY *.java /src/RUN mkdir /app && ls /src && javac /src/PrintXmxXms.java -d /appCMD [“sh”, “-c”, “java -version && java -cp /app PrintXmxXms”]

    這里使用的容器使用舊版本的 Java 8,它早于更新版本中可用的容器支持。構(gòu)建鏡像:

    $ sudo docker build -t oldjava .

    Dockerfile 中的 CMD 行是運行容器時默認執(zhí)行的進程。由于沒有提供-Xmx或-XmsJVM 標志,內(nèi)存設(shè)置將是默認設(shè)置。

    運行容器:

    $ sudo docker run –rm -ti oldjavaopenjdk version “1.8.0_92-internal”OpenJDK Runtime Environment (build 1.8.0_92-…)OpenJDK 64-Bit Server VM (build 25.92-b14, mixed mode)Initial Memory (xms) : 198mbMax Memory (xmx) : 2814mb

    現(xiàn)在使用–memory=1g命令行標志將容器內(nèi)存限制為 1GB:

    $ sudo docker run –rm -ti –memory=1g oldjavaopenjdk version “1.8.0_92-internal”OpenJDK Runtime Environment (build 1.8.0_92-…)OpenJDK 64-Bit Server VM (build 25.92-b14, mixed mode)Initial Memory (xms) : 198mbMax Memory (xmx) : 2814mb

    輸出完全相同。這證明舊的 JVM 沒有遵守容器內(nèi)存限制。

  • JDK 8u130 之后的版本使用相同的測試程序,更改 Dockerfile 的第一行來使用 JVM 8 的新版本:
  • FROM openjdk:8-jdk-alpine

    然后再次做測試:

    $ sudo docker build -t newjava .$ sudo docker run –rm -ti newjavaopenjdk version “1.8.0_212″OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)Initial Memory (xms) : 198mbMax Memory (xmx) : 2814mb

    如上輸出,使用整個 docker 主機內(nèi)存來計算 JVM 堆大小。但是,如果為容器分配 1GB 的 RAM:

    $ sudo docker run –rm -ti –memory=1g newjavaopenjdk version “1.8.0_212″OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)Initial Memory (xms) : 16mbMax Memory (xmx) : 247mb

    這一次,JVM 根據(jù)容器可用的 1GB RAM 計算堆大小。

    現(xiàn)在我們了解了 JVM 如何計算其默認值以及為什么需要一個最新的 JVM 來獲得正確的默認值。

    三、常用的基礎(chǔ)鏡像中內(nèi)存設(shè)置

  • OpenJDK與其直接在容器命令上硬編碼 JVM 標志,不如使用環(huán)境變量。例如在Dockerfile 中使用 JAVA_OPTS 變量,可以在啟動容器時對其進行修改:
  • FROM openjdk:8u92-jdk-alpineCOPY *.java /src/RUN mkdir /app && ls /src && javac /src/PrintXmxXms.java -d /appENV JAVA_OPTS=””CMD [“sh”, “-c”, “java -version && java $JAVA_OPTS -cp /app PrintXmxXms”]

    構(gòu)建鏡像:

    $ sudo docker build -t openjdk-java .

    通過指定JAVA_OPTS環(huán)境變量在運行時選擇內(nèi)存設(shè)置:

    $ sudo docker run –rm -ti -e JAVA_OPTS=”-Xms50M -Xmx50M” openjdk-javaopenjdk version “1.8.0_92-internal”OpenJDK Runtime Environment (build 1.8.0_92-internal-alpine-r1-b14)OpenJDK 64-Bit Server VM (build 25.92-b14, mixed mode)Initial Memory (xms) : 50mbMax Memory (xmx) : 48mb

    注意:-Xmx 參數(shù)和 JVM 報告的 Max memory 之間存在細微差別。這是因為 Xmx 設(shè)置了內(nèi)存分配池的最大大小,其中包括堆、垃圾收集器的幸存者空間和其他池。

    2. Tomcat 9

    Tomcat 9 容器有自己的啟動腳本,因此要設(shè)置 JVM 參數(shù),需要使用這些腳本。

    bin/catalina.sh 腳本要求在環(huán)境變量 CATALINA_OPTS 中設(shè)置內(nèi)存參數(shù)。

    首先需要 創(chuàng)建一個 war 包 部署到 Tomcat。

    然后,我們使用下面的Dockerfile 對其進行容器化,并在其中聲明CATALINA_OPTS環(huán)境變量:

    FROM tomcat:9.0COPY ./target/*.war /usr/local/tomcat/webapps/ROOT.warENV CATALINA_OPTS=”-Xms1G -Xmx1G”

    然后構(gòu)建容器鏡像并運行它:

    $ sudo docker build -t tomcat .$ sudo docker run –name tomcat -d -p 8080:8080 -e CATALINA_OPTS=”-Xms512M -Xmx512M” tomcat

    注意:運行時,將新值傳遞給 CATALINA_OPTS 。如果不提供這個值,會使用 Dockerfile 的第 3 行給出的默認值。

    可以檢查應(yīng)用的運行時參數(shù)并驗證選項-Xmx和-Xms是否存在:

    $ sudo docker exec -ti tomcat jps -lv1 org.apache.catalina.startup.Bootstrap -Xms512M -Xmx512M

    四、使用構(gòu)建插件

    Maven 和 Gradle 提供的插件允許我們在沒有Dockerfile的情況下創(chuàng)建容器鏡像。生成的鏡像通??梢栽谶\行時通過環(huán)境變量進行參數(shù)化。

    下面看幾個例子。

  • 使用 Spring Boot從 Spring Boot 2.3 開始,Spring Boot Maven 和 Gradle 插件可以在沒有 Dockerfile 的情況下高效構(gòu)建容器。
  • 使用 Maven 時,將它們添加到 spring-boot-maven-plugin 中的 塊中:

    com.baeldung.docker heapsizing-demo 0.0.1-SNAPSHOT org.springframework.boot spring-boot-maven-plugin heapsizing-demo

    要構(gòu)建項目,運行下面的命令:

    $ ./mvnw clean spring-boot:build-image

    這將產(chǎn)生一個名為 : 的鏡像。在這個例子中產(chǎn)生的鏡像名為:demo-app:0.0.1-SNAPSHOT。Spring Boot 底層使用 Cloud Native Buildpacks 作為容器化技術(shù)。

    該插件對 JVM 的內(nèi)存設(shè)置進行硬編碼。但是,我們?nèi)匀豢梢酝ㄟ^設(shè)置環(huán)境變量JAVA_OPTS 或 JAVA_TOOL_OPTIONS 來覆蓋:

    $ sudo docker run –rm -ti -p 8080:8080 -e JAVA_TOOL_OPTIONS=”-Xms20M -Xmx20M” –memory=1024M heapsizing-demo:0.0.1-SNAPSHOT

    輸出將與此類似:

    Setting Active Processor Count to 8Calculated JVM Memory Configuration: […][…]Picked up JAVA_TOOL_OPTIONS: -Xms20M -Xmx20M[…]

  • 使用谷歌 JIB就像 Spring Boot maven 插件一樣,Google JIB 無需 Dockerfile 即可高效創(chuàng)建 Docker 鏡像。Maven 和 Gradle 插件以類似的方式配置。Google JIB 還使用環(huán)境變量 JAVA_TOOL_OPTIONS 作為 JVM 參數(shù)的覆蓋機制。
  • 我們可以在任何能夠生成可執(zhí)行 jar 文件的 Java 框架中使用 Google JIB Maven 插件。例如,可以在 Spring Boot 應(yīng)用程序中使用它來代替spring-boot-maven插件來生成容器鏡像:

    com.google.cloud.tools jib-maven-plugin 2.7.1 heapsizing-demo-jib

    鏡像是使用 mvn jib:dockerBuild 命令構(gòu)建的:

    $ mvn clean install && mvn jib:dockerBuild

    嘗試運行:

    $ sudo docker run –rm -ti -p 8080:8080 -e JAVA_TOOL_OPTIONS=”-Xms50M -Xmx50M” heapsizing-demo-jibPicked up JAVA_TOOL_OPTIONS: -Xms50M -Xmx50M[…]2021-01-25 17:46:44.070 INFO 1 — [ main] c.baeldung.docker.XmxXmsDemoApplication : Started XmxXmsDemoApplication in 1.666 seconds (JVM running for 2.104)2021-01-25 17:46:44.075 INFO 1 — [ main] c.baeldung.docker.XmxXmsDemoApplication : Initial Memory (xms) : 50mb2021-01-25 17:46:44.075 INFO 1 — [ main] c.baeldung.docker.XmxXmsDemoApplication : Max Memory (xmx) : 50mb

    五、結(jié)論

    在本文中,我們介紹了需要使用最新的 JVM 來獲取在容器中默認內(nèi)存設(shè)置。

    然后,研究了在自定義容器映像中設(shè)置 -Xms 和 -Xmx 的最佳實踐, 以及如何使用現(xiàn)有 Java 應(yīng)用程序容器在其中設(shè)置 JVM 選項。

    最后,我們看到了如何利用構(gòu)建工具來管理 Java 應(yīng)用程序的容器

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    上一篇 2022年8月7日 19:05
    下一篇 2022年8月7日 19:06

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息