Java 10 との Docker コンテナ統合の改善

ドッカーとジャワ

Apache Spark や Kafka などのデータ サービスや従来のエンタープライズ アプリケーションなど、Java 仮想マシン (JVM) で実行される多くのアプリケーションは、コンテナーで実行されます。 最近まで、コンテナーで JVM を実行すると、メモリと CPU のサイズ設定と使用率に問題が生じ、パフォーマンスが低下していました。 これは、Javaがコンテナで実行されていることを認識しなかったためです。 と 解放 Java 10 では、JVM はコンテナ制御グループ (cgroups) によって設定された制約を認識するようになりました。 メモリー制約と CPU 制約の両方を使用して、Java アプリケーションをコンテナーで直接管理できます。

  • コンテナに設定されたメモリ制限に従う
  • コンテナ内の使用可能な CPU の設定
  • コンテナでの CPU 制約の設定

Java 10 の改善は、Docker for Mac または Windows 環境と Docker Enterprise Edition 環境の両方で実現されています。

コンテナーのメモリ制限

Java 9までは、JVMはフラグを使用してコンテナによって設定されたメモリまたはCPUの制限を認識しませんでした。 Java 10では、メモリ制限が自動的に認識され、適用されます。

ジャワ サーバークラスのマシンを2つのCPUと2GBのメモリを持つものとして定義し、デフォルトのヒープサイズは物理メモリの1/4です。 たとえば、Docker Enterprise Edition のインストールには、2 GB のメモリと 4 つの CPU があります。 Java 8 を実行しているコンテナーと Java 10 を実行しているコンテナーの違いを比較します。 まず、Java 8:

docker container run -it -m512 --entrypoint bash openjdk:latest

$ docker-java-home/bin/java -XX:+PrintFlagsFinal -version |grep MaxHeapSize
    uintx MaxHeapSize := 524288000 {product}
OpenJDK バージョン "1.8.0_162"

最大ヒープ・サイズは、コンテナーに設定された制限を 512M にするのではなく、512M または Docker EE インストールによって設定された 2GB の 1/4 です。 比較すると、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 {製品} {人間工学}
OpenJDK バージョン "10" 2018-03-20

使用可能な 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 シェア 他のすべての実行中のコンテナーの重み付けに対する相対的な重み付け。 この割合は、CPU を集中的に使用するプロセスが実行されている場合にのみ適用されます。 1 つのコンテナー内のタスクがアイドル状態の場合、他のコンテナーは残りの CPU 時間を使用できます。 実際の CPU 時間は、システムで実行されているコンテナーの数によって異なります。 これらはJava 10で設定できます。

docker container run -it --cpu-shares 2048 openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()$1 ==> 2

cpuset 制約は、Java 10 で実行を許可する CPU を設定します。

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

メモリと CPU の割り当て

Java 10 では、コンテナー設定を使用して、アプリケーションのデプロイに必要なメモリーと CPU の割り当てを見積もることができます。 コンテナーで実行されている各プロセスのメモリ ヒープと CPU の要件が既に決定され、JAVA_OPTS設定されていると仮定します。 たとえば、アプリケーションを 10 個のノードに分散させたとします。5 つのノードにはそれぞれ 1024 の CPU シェアを持つ 512Mb のメモリが必要で、別の 5 つのノードにはそれぞれ 512 の CPU シェアを持つ 256Mb が必要です。 1 CPU シェアの割合は 1024 で表されることに注意してください。

メモリの場合、アプリケーションには少なくとも 5 GB を割り当てる必要があります。

512メガバイト x 5 = 2.56ギガバイト

256メガバイト x 5 = 1.28ギガバイト

アプリケーションを効率的に実行するには、8 つの CPU が必要です。

1024 x 5 = 5 CPU

512 x 5 = 3 CPU

ベスト・プラクティスでは、アプリケーションをプロファイルして、JVM で実行されている各プロセスのメモリーと CPU の割り当てを決定することをお勧めします。 ただし、Java 10 では、コンテナーのサイズを決定する際の当て推量を排除して、Java アプリケーションでのメモリー不足エラーを防ぎ、ワークロードを処理するのに十分な CPU を割り当てます。

Java 開発者向けの Docker ソリューションの詳細については、以下を参照してください。

 

フィードバック

「Java 0とのDockerコンテナ統合の改善」に関する10の考え