コンテナ内の JVM リソースを安全に制限するにはどうすればよいですか?

コンテナ内の JVM リソースを安全に制限するにはどうすればよいですか?

  [[254653]]

序文

Java と Docker の組み合わせにより、アプリケーションのパッケージ化の問題がより適切に解決されました。しかし、互換性がない部分もあります。たとえば、Java は Docker によって設定されたメモリ制限と CPU 制限を自動的に検出できません。

これにより、JVM はビジネスに安定して対応できなくなります。コンテナは JVM プロセスを強制終了し、ヘルス チェックによって JVM プロセスがプルアップされるため、ポッドが 1 日に何百回も再起動する可能性があることを監視できます。

Java プロセスがコンテナ内で実行されるときに、Kubernetes YAML 記述ファイルでコンテナと JVM パラメータを毎回構成しなくても、Java がコンテナの制限を自動的に識別し、正しいメモリと CPU 情報を取得できるようになることを期待しています。

JVM MaxRAM パラメータまたは JVM パラメータを使用して実験的な機能のロックを解除し、JDK を 10 以上にアップグレードすると、この問題を解決できます (おそらく~.~)。

まず、Docker コンテナは本質的にはホスト マシン上のプロセスです。ホストマシンと /proc ディレクトリを共有します。つまり、コンテナ内で表示される /proc/meminfo と /proc/cpuinfo は、以下に示すように、ホスト マシン上で直接表示されるものと一致しています。

ホスト

  1. /proc/meminfo を cat する
  2. メモリ合計: 197869260 kB
  3. メモリ空き容量: 3698100 kB
  4. 利用可能なメモリ: 62230260 kB

容器

  1. docker run -it --rm alpine cat /proc/meminfo  
  2. メモリ合計: 197869260 kB
  3. メモリ空き容量: 3677800 kB
  4. 利用可能なメモリ: 62210088 kB

では、Java はどのようにしてホストのメモリ情報を取得するのでしょうか?そうです、/proc/meminfo を通じて取得されます。

デフォルトでは、JVM の最大ヒープ サイズはシステム メモリの 1/4 です。システムが 8G の場合、JVM のデフォルトのヒープは約 2G になります。

Docker は CGroups を使用してメモリを制限し、/proc ディレクトリは読み取り専用形式でコンテナーにマウントされます。デフォルトでは、Java は CGroups によって制限されるメモリ サイズをまったく認識できず、起動時のメモリ情報として /proc/meminfo の情報を使用します。この非互換性により、コンテナに割り当てられたメモリが JVM のメモリよりも少ない場合、JVM プロセスが強制終了されます。

互換性のないメモリ制限

まず、一連のテストを見てみましょう。ここでは、188G のメモリを搭載した物理マシンを使用します。

  1. # free -g 合計使用済み空き共有バッファ/キャッシュ使用可能
  2. メンバー: 188 122 1 0 64 64

以下のテストでは、openjdk のホットスポット仮想マシンと IBM の openj9 仮想マシンを使用します。

次のテストでは、正しく安全であると識別された JDK (つまり、コンテナの制限を超えず、強制終了されない) と、誤って危険であると識別された JDK と呼びます。

テストケース1 (OPENJDK)

この一連のテストでは、最新の openjdk8-12 を使用し、コンテナ メモリを 4G に制限し、JDK のデフォルト パラメータでの最大ヒープを確認します。デフォルトのパラメータで安全な JDK のバージョンがいくつあるか確認してみましょう。

コマンドは以下のとおりです。試してみたい場合は、コマンドを使用できます。

  1. docker run -m 4GB --rm openjdk:8-jre-slim java -XshowSettings:vm -version  
  2. docker run -m 4GB --rm openjdk:9-jre-slim java -XshowSettings:vm -version  
  3. docker run -m 4GB --rm openjdk:10-jre-slim java -XshowSettings:vm -version  
  4. docker run -m 4GB --rm openjdk:11-jre-slim java -XshowSettings:vm -version  
  5. docker run -m 4GB --rm openjdk:12 java -XshowSettings:vm -version  

OpenJDK8 (コンテナ制限を認識しない、26.67G) 危険

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm openjdk:8-jre-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 26.67G
  4. 人間工学マシンクラス: サーバー
  5. VM の使用: OpenJDK 64ビットサーバー VM
  6. openjdk バージョン"1.8.0_181"  
  7. OpenJDK ランタイム環境 (ビルド 1.8.0_181-8u181-b13-2~deb9u1-b13)
  8. OpenJDK 64ビットサーバー VM (ビルド 25.181-b13、混合モード)

OpenJDK8 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap (コンテナ制限を正しく識別、910.50M) 安全性

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm openjdk:8-jre-slim java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 910.50M
  4. 人間工学マシンクラス: サーバー
  5. VM の使用: OpenJDK 64ビットサーバー VM
  6. openjdk バージョン"1.8.0_181"  
  7. OpenJDK ランタイム環境 (ビルド 1.8.0_181-8u181-b13-2~deb9u1-b13)
  8. OpenJDK 64ビットサーバー VM (ビルド 25.181-b13、混合モード)

OpenJDK 9(コンテナ制限を認識していない、26.67G)は危険です

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm openjdk:9-jre-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 29.97G
  4. VM の使用: OpenJDK 64ビットサーバー VM
  5. openjdk バージョン"9.0.4"  
  6. OpenJDK ランタイム環境 (ビルド 9.0.4+12-Debian-4)
  7. OpenJDK 64ビットサーバー VM (ビルド 9.0.4+12-Debian-4、混合モード)

OpenJDK 9 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap (コンテナ制限を正しく識別、1G) 安全性

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm openjdk:9-jre-slim java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 1.00G
  4. VM の使用: OpenJDK 64ビットサーバー VM
  5. openjdk バージョン"9.0.4"  
  6. OpenJDK ランタイム環境 (ビルド 9.0.4+12-Debian-4)
  7. OpenJDK 64ビットサーバー VM (ビルド 9.0.4+12-Debian-4、混合モード)

OpenJDK 10 (コンテナ制限の正しい識別、1G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 32GB --rm openjdk:10-jre-slim java -XshowSettings:vm -XX:MaxRAMFraction=1 -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 1.00G
  4. VM の使用: OpenJDK 64ビットサーバー VM
  5. openjdk バージョン「10.0.2」 2018-07-17
  6. OpenJDK ランタイム環境 (ビルド 10.0.2+13-Debian-2)
  7. OpenJDK 64ビットサーバー VM (ビルド 10.0.2+13-Debian-2、混合モード)

OpenJDK 11 (コンテナ制限の正しい識別、1G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm openjdk:11-jre-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 1.00G
  4. VM の使用: OpenJDK 64ビットサーバー VM
  5. openjdk バージョン「11.0.1」 2018-10-16
  6. OpenJDK ランタイム環境 (ビルド 11.0.1+13-Debian-3)
  7. OpenJDK 64ビットサーバー VM (ビルド 11.0.1+13-Debian-3、混合モード、共有)

OpenJDK 12 (コンテナ制限の正しい識別、1G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm openjdk:12 java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 1.00G
  4. VM の使用: OpenJDK 64ビットサーバー VM
  5. openjdk バージョン「12-ea」 2019-03-19
  6. OpenJDK ランタイム環境 (ビルド 12-ea+23)
  7. OpenJDK 64ビットサーバー VM (ビルド 12-ea+23、混合モード、共有)

テストケース2 (IBM OPEN J9)

  1. docker run -m 4GB --rm adoptopenjdk/openjdk8-openj9:alpine-slim java -XshowSettings:vm -version  
  2. docker run -m 4GB --rm adoptopenjdk/openjdk9-openj9:alpine-slim java -XshowSettings:vm -version  
  3. docker run -m 4GB --rm adoptopenjdk/openjdk10-openj9:alpine-slim java -XshowSettings:vm -version  
  4. docker run -m 4GB --rm adoptopenjdk/openjdk11-openj9:alpine-slim java -XshowSettings:vm -version  

openjdk8-openj9 (コンテナ制限を正しく識別、3G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm adoptopenjdk/openjdk8-openj9:alpine-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 3.00G
  4. 人間工学マシンクラス: サーバー
  5. VMの使用: Eclipse OpenJ9 VM
  6. openjdk バージョン"1.8.0_192"  
  7. OpenJDK ランタイム環境 (ビルド 1.8.0_192-b12_openj9)
  8. Eclipse OpenJ9 VM (ビルド openj9-0.11.0、JRE 1.8.0 Linux amd64-64ビット圧縮参照20181107_95 (JIT 有効、AOT 有効)
  9. オープンJ9 - 090ff9dcd
  10. OMR-ea548a66
  11. JCL - b5a3affe73 (jdk8u192-b12基づく)

openjdk9-openj9 (コンテナ制限を正しく識別、3G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm adoptopenjdk/openjdk9-openj9:alpine-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 3.00G
  4. VMの使用: Eclipse OpenJ9 VM
  5. openjdk バージョン「9.0.4-adoptopenjdk」  
  6. OpenJDK ランタイム環境 (ビルド 9.0.4-adoptopenjdk+12)
  7. Eclipse OpenJ9 VM (ビルド openj9-0.9.0、JRE 9 Linux amd64-64ビット圧縮参照20180814_248 (JIT 有効、AOT 有効)
  8. オープンJ9 - 24e53631
  9. OMR-fad6bf6e
  10. JCL - feec4d2ae ( jdk-9.0.4+12 ベース)

openjdk10-openj9 (コンテナ制限を正しく識別、3G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm adoptopenjdk/openjdk10-openj9:alpine-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 3.00G
  4. VMの使用: Eclipse OpenJ9 VM
  5. openjdk バージョン"10.0.2-adoptopenjdk" 2018-07-17
  6. OpenJDK ランタイム環境 (ビルド 10.0.2-adoptopenjdk+13)
  7. Eclipse OpenJ9 VM (ビルド openj9-0.9.0、JRE 10 Linux amd64-64ビット圧縮参照20180813_102 (JIT 有効、AOT 有効)
  8. オープンJ9 - 24e53631
  9. OMR-fad6bf6e
  10. JCL - 7db90eda56 ( jdk-10.0.2+13 ベース)

openjdk11-openj9 (コンテナ制限の正しい識別、3G) セキュリティ

  1. [root@xiaoke-test ~]# docker run -m 4GB --rm adoptopenjdk/openjdk11-openj9:alpine-slim java -XshowSettings:vm -version  
  2. VM設定:
  3. マックス。ヒープサイズ(推定): 3.00G
  4. VMの使用: Eclipse OpenJ9 VM
  5. openjdk バージョン「11.0.1」 2018-10-16
  6. OpenJDK ランタイム環境 AdoptOpenJDK (ビルド 11.0.1+13)
  7. Eclipse OpenJ9 VM AdoptOpenJDK (ビルド openj9-0.11.0、JRE 11 Linux amd64-64ビット圧縮参照20181020_70 (JIT 有効、AOT 有効)
  8. オープンJ9 - 090ff9dc
  9. OMR-ea548a66
  10. JCL - f62696f378 ( jdk-11.0.1+13 ベース)

分析する

分析する前に、まずこのような状況を理解しましょう。

JavaMemory (MaxRAM) = メタデータ + スレッド + コード キャッシュ + OffHeap + ヒープ...

通常はヒープのみを構成します。つまり、-Xmx を使用して JVM が使用できる最大ヒープを指定します。これは、JVM が取得する最大メモリの 1/4 をデフォルトでヒープとして使用する理由でもあります。

安全性(つまり、コンテナの制限を超えてコンテナによって殺されることはありません)

オープンJDK

OpenJdk8-12 はこのセキュリティ機能を保証できます (8 と 9 では特別なパラメータ -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap が必要です)。

オープンJ9

2. IbmOpenJ9 のすべてのバージョンはコンテナー制限を認識できます。

リソースの利用

オープンJDK

OpenJdk はコンテナの制限を自動的に識別した後、最大ヒープをコンテナ メモリの約 1/4 に設定しますが、これはメモリの大きな無駄になります。

もちろん、別の JVM パラメータを使用して *** ヒープを設定することもできます。 -XX:MaxRAMFraction=int。以下は私がまとめた一般的なメモリ設定の表です。このことから、JVM のデフォルトの最大ヒープ値は MaxRAMFraction=4 であることがわかります。メモリが増加すると、ヒープのアイドル領域はますます大きくなります。コンテナ メモリが 16G の場合、Java ヒープは 4G 未満になります。

  1. MaxRAMFraction 値 ヒープ比 コンテナ メモリ = 1G コンテナ メモリ = 2G コンテナ メモリ = 4G コンテナ メモリ = 8G コンテナ メモリ = 16G
  2. 1 ≈90% 910.50M 1.78G 3.56G 7.11G 14.22G
  3. 2 ≈50% 455.50M 910.50M 1.78G 3.56G 7.11G
  4. 3 ≈33% 304.00M 608.00M 1.19G 2.37G 4.74G
  5. 4 ≈25% 2億2,800万 4億5,550万 9億1,050万 178万 356万

オープンJ9

OpenJ9 の詳細については、こちらをご覧ください。 OpenJ9 のメモリ利用戦略は OpenJdk よりも優れています。以下はOpenJ9ポリシーテーブルです

  1. コンテナメモリ <サイズ> ***Java ヒープサイズ
  2. 1 GB 未満 50 % <サイズ>
  3. 1 GB - 2 GB <サイズ> - 512 MB
  4. 2 GB以上 2 GB以上

結論は

注: ここでは、物理マシンのメモリとは異なるコンテナのメモリ制限について説明します。

自動

-Xmx を明示的に指定せずに、Java プロセスがコンテナーの制限を自動的に検出できるようにしたい場合。

1. JVM プロセスをコンテナによって強制終了されることなくコンテナ内で安全かつ安定して実行する必要がある場合、JDK バージョンが 10 未満の場合 (JDK10 以上のバージョンを設定する必要はありません。前のテストを参照してください)、メモリの問題により Java プロセスがコンテナによって強制終了されないように、JVM パラメータ -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap を追加で設定する必要があります。もちろん、この方法は使い方が簡単で信頼性が高いですが、欠点も明らかです。リソースの使用率が低すぎるのです (前の表の MaxRAMFraction=4 を参照)。

2. メモリ リソースの使用率を向上させたい場合、コンテナ メモリが 1 GB ~ 4 GB の場合は、-XX:MaxRAMFraction=2 を設定することをお勧めします。コンテナ メモリが 8 GB を超える場合は、-XX:MaxRAMFraction=1 の設定を試してください (上記の表を参照)。

マニュアルトランスミッション

手動送信エクスペリエンスを希望し、メモリ リソースをさらに活用する場合は、手動構成時代 -Xmx に戻る必要がある場合があります。マニュアルトランスミッション部分については、上記の私のBBを完全に無視してください。

1. 上記では、非常にシンプルで使いやすい自動設定について説明しました。コンテナの制限は自動的に検出されるため、-Xmx の構成について心配したり考えたりする必要はありません。

2. たとえば、1G のメモリがある場合は -Xmx750M、2G の場合は -Xmx1700M、4G の場合は -Xmx3500-3700M、8G の場合は -Xmx7500-7600M に設定することをお勧めします。つまり、JVM のその他のメモリ用に少なくとも 300 MB のメモリを予約する必要があります。ヒープが特に大きい場合は、1G または 2G を予約できます。

3. マニュアルトランスミッションはそれほど使い心地は良くありませんが、当然ながらリソースの利用率は比較的高くなります。

<<:  仮想化プラットフォームが 3 分で何ができるのか理解できますか?

>>:  なぜ人々はクラウド コンピューティングを十分に信頼しないのでしょうか?

推薦する

地元の装飾や建築資材のウェブサイトは危険に満ちている

インターネットの発展に伴い、オンラインショッピングは生活の各分野に溶け込んでおり、佳天下、淘宝ホーム...

DistributedVideoPlayer 分散ビデオプレーヤー (パート 2)

[[430308]]詳細については、以下をご覧ください。 51CTOとHuaweiが共同で構築したH...

ファーウェイのホウ・ジンロン氏:フルシナリオインテリジェンスを構築し、世界クラスの「スマート深セン」を創造する

【中国・深セン、2020年7月28日】本日、「スマート深セン、前進」をテーマにしたファーウェイクラウ...

ブログマーケティングとWeiboマーケティングの3つの違い

近年、新浪微博の急速な台頭により、微博の概念が広く普及し、人々は徐々に微博を理解し、受け入れ始めまし...

初心者向けウェブサイト向けロングテールキーワードマイニングの実践的なチュートリアル

ロングテールキーワードは通常 2 ~ 3 語で構成されますが、短いドメインになることもあります。 S...

率先して行動し、冷静さを保つ: Kubernetes クラスターの積極的な拡張

クラスター リソースが不足している場合、Cluster Autoscaler は新しいノードをプロビ...

タオバオモバイルは12の印刷メディアと提携し、メディア電子商取引の分野をテストするためにタオバオを立ち上げた。

新浪科技は4月1日午前、アリババが本日、タオバオモバイルと全国12の主流新聞社との戦略的提携「馬商淘...

オンラインマーケティング8年の経験:中小企業がQ&Aマーケティングを実施する方法

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービスAR Zhuifeng ...

海外のSEOフォーラムで議論されたいくつかの小さな問題

以下は、いくつかの海外 SEO フォーラムで多くのクリックと返信があった小さな質問です。参考までにご...

SEOコンテンツは王様:疑似オリジナルコンテンツを作成する方法

SEO体験記事の中で「疑似オリジナリティ」という概念について触れている人は多いです。一般的にはタイト...

インターネットの素人から見たインターネットマーケティングとプロモーション

実は私は、貴金属関係の会社でインターネットとは関係のない技術系の仕事をしている技術者です。興味があっ...

51CTO 独占: 2011 IBM クラウド コンピューティング サミットの秘密

北京から上海まで1,400キロ以上あります。私と私の同僚は、明日 IBM が開催する2011 クラウ...

王志全:Dapuはどのようにして良い製品を作っているのでしょうか?

【iTianxia.comからのお知らせ】Dapuはコストパフォーマンスに優れたインナーテキスタイル...

外部リンク構築におけるよくある誤解の簡単な分析

外部リンク構築におけるよくある誤解の簡単な分析ご存知のとおり、ウェブサイトが上位にランクインするには...