回覆列表
  • 1 # 小樣醬

    如果使用官方的Java映象,或者基於Java映象構建的Docker映象,都可以透過傳遞 JAVA_OPTS 環境變數來輕鬆地設定JVM的記憶體引數。比如,對於官方Tomcat 映象,我們可以執行下面命令來啟動一個最大記憶體為512M的tomcat例項

    docker run --rm -e JAVA_OPTS="-Xmx512m" tomcat:8

    在日誌中,我們可以清楚地發現設定已經生效 “Command line argument: -Xmx512m”

    02-Apr-2016 12:46:26.970 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version: Apache Tomcat/8.0.32

    02-Apr-2016 12:46:26.974 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Feb 2 2016 19:34:53 UTC

    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number: 8.0.32.0

    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux

    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 4.1.19-boot2docker

    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64

    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/lib/jvm/java-7-openjdk-amd64/jre

    02-Apr-2016 12:46:26.976 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.7.0_95-b00

    02-Apr-2016 12:46:26.976 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation

    02-Apr-2016 12:46:26.977 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat

    02-Apr-2016 12:46:26.977 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat

    02-Apr-2016 12:46:26.978 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties

    02-Apr-2016 12:46:26.978 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager

    02-Apr-2016 12:46:26.978 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx512m

    ...

    然而在Docker叢集上部署執行Java容器應用的時候,僅僅對JVM的heap引數設定是不夠的,我們還需要對Docker容器的記憶體資源進行限制:

    1. 限制容器使用的記憶體的最大量,防止對系統或其他應用造成傷害

    2. 能夠將Docker容器排程到擁有足夠空餘的記憶體的節點,從而保證應用的所需執行資源

    關於容器的資源分配約束,Docker提供了相應的啟動引數

    對記憶體而言,最基本的就是透過 -m引數來約束容器使用記憶體的大小

    -m, --memory=""

    Memory limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M.

    那麼問題就來了,為了正確設定Docker容器記憶體的大小,難道我們需要同時傳遞容器的記憶體限制和JAVA_OPTS環境變數嗎? 如下所示:

    docker run --rm -m 512m -e JAVA_OPTS="-Xmx512m" tomcat:8

    這個方法有兩個問題

    1. 需要管理員保證容器記憶體和JVM記憶體設定匹配,否則可能引發錯誤

    2. 當對容器記憶體限制調整時,環境變數也需要重新設定,這就需要重建一個新的容器

    是否有一個方法,可以讓容器內部的JVM自動適配容器的記憶體限制?這樣可以採用更加統一的方法來進行資源管理,簡化配置工作。

    大家知道Docker是透過CGroup來實現資源約束的,自從1.7版本之後,Docker把容器的local cgroups以只讀方式掛載到容器內部的檔案系統上,這樣我們就可以在容器內部,透過cgroups資訊來獲取系統對當前容器的資源限制了。

    我建立了一個示例映象 registry.aliyuncs.com/denverdino/tomcat:8-autoheap

    ,其原始碼可以從Github 獲得。它基於Docker官方Tomcat映象建立,它的啟動指令碼會檢查CGroup中記憶體限置,並計算JVM最大Heap size來傳遞給Tomcat。其程式碼如下

    #!/bin/bash

    limit_in_bytes=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)

    # If not default limit_in_bytes in cgroup

    if [ "$limit_in_bytes" -ne "9223372036854771712" ]

    then

    limit_in_megabytes=$(expr $limit_in_bytes \/ 1048576)

    heap_size=$(expr $limit_in_megabytes - $RESERVED_MEGABYTES)

    export JAVA_OPTS="-Xmx${heap_size}m $JAVA_OPTS"

    echo JAVA_OPTS=$JAVA_OPTS

    fi

    exec catalina.sh run

    說明:

    為了監控,故障排查等場景,我們預留了部分記憶體(預設64M),其餘容器記憶體我們都分配給JVM的堆。

    這裡沒有對邊界情況做進一步處理。在生產系統中需要根據情況做相應的設定,比如最大的堆大小等等。

    現在我們啟動一個tomcat執行在512兆的容器中

    docker run -d --name test -m 512m registry.aliyuncs.com/denverdino/tomcat:8-autoheap

    透過下列命令,從日誌中我們可以檢測到相應的JVM引數已經被設定成 448MB (512-64)

    docker logs test

    ...

    02-Apr-2016 14:18:09.870 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx448m

    ...

    我們也可以方便的調整Java應用的記憶體.

    Docker 1.10提供了對容器資源限制的動態修改能力。但是由於JVM無法感知容器資源修改,我們依然需要重啟tomcat來變更JVM的記憶體設定,例如,我們可以透過下面命令把容器記憶體限制調整到1GB

    docker update -m 1024m test

    docker restart test

    再次檢查日誌,相應的JVM Heap Size最大值已被設定為960MB

    docker logs test

    ...

    02-Apr-2016 14:21:07.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx960m

  • 中秋節和大豐收的關聯?
  • 怎樣撕醫用膠帶不痛?