コンテナ内の 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 分で何ができるのか理解できますか?

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

推薦する

OpenTelemetryに基づくフルリンクトレース

可観測性 - 鳥瞰図前の記事で述べたように、可観測性とは、システムによって生成された外部データ (ロ...

ウェブサイトの診断と最適化: キーワードマイニング手法

前回の周旭生の記事では、「初心者が身につけるべきウェブサイト診断と最適化のスキル」を紹介しました。前...

dotvps - 3g メモリ/50g ハードディスク/1000g トラフィック/4 データセンター/月額 7 ドル

dotvps は、3G メモリ、月額 7 ドル、オプションのデータ センター 4 つ、openvz ...

Huawei Cloud Distributed Cache Redis サービスが企業のデータ処理を加速

Huawei Cloud Distributed Cache Redis サービスは、Redis と...

クラウドコンピューティングはデータセンターの運用と開発をどのように変えるのか

今日、情報技術は絶えず発展しています。そして、この技術の進歩は猛烈な勢いで進み続け、より高速な処理と...

StreamNativeは、クラウドネイティブ業界の高速な前進を支援するために、Tencent Cloud Native Acceleratorに正式に参加しました。

近年、インターネットのイノベーションは、消費者向けインターネットから産業向けインターネットへと変化し...

新しいウェブサイトの百度重みが3に達し、40日間でトラフィックが1,000を超えた理由について簡単に説明します。

社内でプロモーション業務をしていたため、ソフトな記事を書く必要があったのですが、公開プラットフォーム...

ウェブページにおけるキーワード配信技術の詳細な説明

蘭州SEOのヤン・ファン氏はかつて、「ウェブサイトのランキングを迅速に向上させるキーワードの選択」と...

企業のデジタルトランスフォーメーションにおけるクラウド利用の現状に関する調査:ハイブリッドクラウドに関する誤解は依然として存在する

この疫病によりデジタル化の早送りボタンが押され、より多くの企業がデジタル変革の重要性と緊急性を認識す...

#中秋国庆# uuuvps: 香港 VPS は年間 97 元から、CN2+bgp ネットワーク、高性能、強力な構成

uuuvps (登録番号 2869262、ID はこちらをクリック) は国慶節と中秋節を祝います。当...

ウェブマスターネットワークからの毎日のレポート:百度が年間検索ランキングを発表、KubaとGomeが合併

1. 百度が2012年の年間検索ランキングを発表百度は2012年の年間検索チャートを発表した(htt...

安価なストレージスペース: interserver、月額 10 ドル、4 TB のストレージ/10 TB のトラフィック、ニューヨーク データ センター、米国

インターサーバー(1999年~)は、米国ニューヨークのデータセンターでストレージスペースサービスを提...

クラウドセキュリティに影響を与える3つの要素

企業はクラウド プラットフォームに移行しており、CIO はセキュリティに関する考え方を変える必要に迫...

Kubernetes プローブの落とし穴

[[342084]]この記事はWeChatの公開アカウント「Dotnet Plus」から転載したもの...

Vultr-2.5 USD/KVM/512M メモリ/20g SSD/日本/シンガポールなどに 15 のデータセンター。

Vultr VPS は、VPS 構成の包括的なアップグレードと価格の引き下げという変更を開始していま...