Java は、活発なオープン ソース コミュニティと完全な環境上の利点により、過去 20 年間で最も人気のあるプログラミング言語の 1 つとなっています。クラウドネイティブ時代に入り、急成長するクラウドネイティブテクノロジーは、クラウドコンピューティングの利益を解き放ち、ビジネスのクラウドネイティブ変革を促進し、企業のデジタル変革を加速します。 しかし、Java のクラウド ネイティブ変換には大きな課題が伴います。 Java の動作メカニズムとクラウドネイティブの特性の間には多くの矛盾があります。企業はクラウドネイティブテクノロジーを使用して徹底的なコスト最適化を実施し、リソースコスト管理はかつてないレベルにまで引き上げられました。パブリック クラウド上のリソースは使用量に基づいて課金されるため、ユーザーはリソース使用量に非常に敏感です。メモリ使用量の点では、Java 仮想マシンに基づく実行メカニズムにより、どの Java プログラムにも固定の基本メモリ オーバーヘッドが発生します。 C++/Golangなどのネイティブ言語と比較すると、Javaアプリケーションは膨大な量のメモリを占有し、「メモリイーター」と呼ばれます。したがって、Java アプリケーションをクラウドに移行するにはコストがかかります。さらに、アプリケーションがクラウドに統合されると、システムの複雑さが増します。一般ユーザーは、クラウド上の Java アプリケーションのメモリを明確に理解しておらず、アプリケーションのメモリを適切に構成する方法を知りません。 OOM 問題が発生すると、トラブルシューティングが困難になり、多くの問題が発生します。 ヒープメモリが Xmx を超えていないのに OOM が発生するのはなぜですか?オペレーティング システムと JVM 間のメモリ関係を理解するにはどうすればよいでしょうか?プログラムが占有するメモリが Xmx を超えるのはなぜですか?メモリはどこで使用されますか?オンライン コンテナー内のプログラムにより多くのメモリが必要なのはなぜですか?この記事では、クラウドネイティブ Java アプリケーションの進化の実践において EDAS ユーザーが遭遇する問題を分析し、クラウドネイティブ Java アプリケーションのメモリ構成に関する推奨事項を示します。 1. 背景知識K8s アプリケーションのリソース構成クラウドネイティブ アーキテクチャは K8s に基づいています。アプリケーションは K8s にデプロイされ、コンテナ グループの形式で実行されます。 K8s リソース モデルには、リソース要求とリソース制限の 2 つの定義があります。 K8s は、コンテナに要求された数のリソースがあることを保証しますが、コンテナが制限数を超えるリソースを使用することを許可しません。次のメモリ構成を例にとると、コンテナは少なくとも 1024Mi のメモリ リソースを取得できますが、4096Mi を超えることはできません。メモリ使用量が制限を超えると、コンテナは OOM 状態になり、K8s コントローラによって再起動されます。 コンテナOOMコンテナの OOM メカニズムについては、まずコンテナの概念を確認する必要があります。コンテナについて話すとき、これはサンドボックス テクノロジであると言われます。サンドボックスとして、コンテナは内部で比較的独立しており、境界とサイズがあります。コンテナ内の独立した動作環境は、Linux 名前空間メカニズムを通じて実装されます。コンテナ内の PID、マウント、UTS、IPD、ネットワークなどの名前空間は隠されているため、ホストの名前空間や他のコンテナの名前空間はコンテナ内では見えません。いわゆるコンテナの境界とサイズは、コンテナによる CPU、メモリ、IO、その他のリソースの使用に対する制約を指します。そうしないと、単一のコンテナが多くのリソースを占有しすぎて、他のコンテナの実行速度が低下したり、異常な動作をしたりする可能性があります。 cgroup は、Linux カーネルによって提供されるメカニズムであり、単一のプロセスまたは複数のプロセスによって使用されるリソースを制限できます。これは、コンテナ リソース制約を実装するためのコア テクノロジーでもあります。コンテナは、オペレーティング システムの観点から見ると、単なる特別なプロセスにすぎません。プロセスのリソース使用量は、Cgroup の制約に従います。プロセスによって使用されるメモリの量が Cgroup 制限を超えると、システムの OOM Killer によって容赦なくプロセスが強制終了されます。 したがって、いわゆるコンテナ OOM は、実際には Linux システム上で実行されているコンテナ プロセスに OOM があることを意味します。 Cgroup は、あまり知られていないテクノロジーではありません。 Linux ではこれをファイル システムとして実装しており、これはすべてがファイルであるという Unix の哲学と一致しています。 Cgroup V1 の場合、コンテナ内の /sys/fs/cgroup/ ディレクトリで現在のコンテナの Cgroup 構成を直接表示できます。 コンテナ メモリの場合、memory.limit_in_bytes と memory.usage_in_bytes は、メモリ制御グループで最も重要な 2 つのパラメーターです。前者は現在のコンテナ プロセス グループで使用できるメモリの最大値を識別し、後者は現在のコンテナ プロセス グループで実際に使用されているメモリの合計です。一般的に、使用値が最大値に近いほど、OOM のリスクが高くなります。 JVM の OOMOOM に関しては、Java 開発者は JVM OOM に精通しています。 JVM にオブジェクト用のスペースを割り当てるための十分なメモリがなく、ガベージ コレクターに再利用するスペースがない場合、java.lang.OutOfMemoryError がスローされます。 JVM 仕様によれば、プログラム カウンターを除く他のメモリ領域で OOM が発生する可能性があります。最も一般的な JVM OOM 状況は次のとおりです。
2. ヒープメモリが Xmx を超えていないのに OOM が発生するのはなぜですか?多くの人がこのシナリオに遭遇したことがあると思います。 K8s にデプロイされた Java アプリケーションは頻繁に再起動され、コンテナの終了ステータスは終了コード 137、理由: OOM Killed となります。すべての情報は明らかな OOM を示しています。ただし、JVM 監視データは、ヒープ メモリ使用量が最大ヒープ メモリ制限 Xmx を超えていないことを示しています。 OOM 自動ヒープダンプ パラメータが設定されると、OOM が発生してもダンプ ファイルは生成されません。 上記の背景知識によれば、コンテナ内の Java アプリケーションでは、JVM OOM とコンテナ OOM という 2 種類の OOM 例外が発生する可能性があります。 JVM OOM は、JVM メモリ領域のスペース不足によって発生するエラーです。 JVM は積極的にエラーをスローし、プロセスを終了します。データを観察すると、メモリ使用量が制限を超えていることがわかります。JVM は対応するエラー レコードを残します。コンテナの OOM はシステムの動作です。コンテナ プロセス グループ全体で使用されるメモリが Cgroup 制限を超え、システム OOM Killer によって強制終了されます。関連する記録はシステム ログと K8s イベントに残されます。 一般に、Java プログラムのメモリ使用量は、JVM と Cgroup の両方からの制限を受けます。 Java ヒープ メモリは Xmx パラメータによって制限されます。制限を超えると、JVM OOM が発生します。プロセス全体のメモリは、コンテナのメモリ制限値によって制限されます。制限を超えると、コンテナ OOM が発生します。 OOM を識別してトラブルシューティングし、必要に応じて構成を調整するには、観測データ、JVM エラー レコード、システム ログ、K8s イベントを組み合わせる必要があります。 3. オペレーティング システムと JVM 間のメモリ関係を理解するにはどうすればよいでしょうか?前述のように、Java コンテナの OOM は、実際には、Java プロセスによって使用されるメモリが Cgroup 制限を超え、オペレーティング システムの OOM Killer によって強制終了されることを意味します。では、オペレーティング システムの観点から、Java プロセスのメモリをどのように見ればよいのでしょうか?オペレーティング システムと JVM にはそれぞれ独自のメモリ モデルがあります。これら 2 つはどのようにマッピングされますか? Java プロセスにおける OOM の問題を調査するには、JVM とオペレーティング システム間のメモリ関係を理解することが重要です。 最も一般的に使用される OpenJDK を例にとると、JVM は基本的にオペレーティング システム上で実行される C++ プロセスであるため、そのメモリ モデルも Linux プロセスの一般的な特性を備えています。 Linux プロセスの仮想アドレス空間は、カーネル空間とユーザー空間に分かれています。ユーザー空間はさらに多くのセグメントに分割されます。ここでは、この記事に関連性の高いいくつかのセグメントを選択して、JVM メモリとプロセス メモリのマッピング関係について説明します。
前述のように、ヒープ スペースは Linux プロセス メモリ レイアウトと JVM メモリ レイアウトの両方に共通する概念です。それは最も混乱を招き、最も異なる概念です。 Java ヒープは Linux プロセス ヒープよりも小さくなります。これは、JVM によってプロセス ヒープ領域上に作成される論理領域です。プロセス ヒープ スペースには、Java スレッド スタック、コード キャッシュ、GC、コンパイラ データなど、JVM 仮想マシンの動作をサポートするメモリ データも含まれます。 4. プログラムが占有するメモリが Xmx を超えるのはなぜですか?メモリはどこで使用されますか?実は、誰もがよく知っているヒープ メモリに加えて、JVM には非ヒープ メモリと呼ばれるものもあります。 JVM によって管理されるメモリに加えて、JVM をバイパスせずに直接開かれるローカル メモリもあります。 Java プロセスのメモリ使用量は、次のように簡単にまとめることができます。 JDK8 では、JVM の内部メモリ使用量を追跡できるネイティブ メモリ トラッキング (NMT) 機能が導入されました。デフォルトでは、NMT は無効になっています。 JVM パラメータを使用して有効にします: -XX:NativeMemoryTracking=[off |概要 |詳細] ここでは、最大ヒープメモリは 300M に制限され、GC アルゴリズムとして G1 が使用され、プロセスのメモリ使用量を追跡するために NMT が有効になっています。 注意: NMT を有効にすると、5% ~ 10% のパフォーマンス オーバーヘッドが発生します。 NMT を有効にすると、jcmd コマンドを使用して JVM メモリ使用量を出力できます。ここではメモリの概要情報のみを表示でき、設定単位は MB です。 JVM 合計メモリ
NMT レポートによると、プロセスには現在 1764 MB の予約済みメモリと 534 MB のコミット済みメモリがあり、これは最大ヒープ メモリの 300 MB を大幅に上回っています。予約とは、プロセスが使用できるメモリの量として理解できる、プロセスに対して連続した仮想アドレス メモリを開くことを指します。送信とは、仮想アドレスを物理メモリにマッピングすることを指し、これはプロセスによって現在占有されているメモリの量として理解できます。 NMT によってカウントされるメモリは、オペレーティング システムによってカウントされるメモリとは異なることに注意してください。 Linux はメモリを割り当てるときに遅延割り当てメカニズムに従います。プロセスが実際にアクセスした場合にのみ、メモリ ページを物理メモリにスワップします。したがって、top コマンドで表示されるプロセスの物理メモリ使用量は、NMT レポートで表示されるものとは異なります。ここでは、JVM の観点からメモリ使用量を示すために NMT のみが使用されます。 Javaヒープ
Java ヒープメモリはそのまま設定され、実際に 300M のメモリ空間が解放されます。 メタスペース
ロードされたクラスは Metaspace に保存され、11,183 個のクラスがロードされ、約 1G が保持され、61M が送信されます。 ロードするクラスが増えるほど、Metaspace の使用量も増えます。メタスペースのサイズは、-XX:MaxMetaspaceSize (デフォルトでは無制限) と -XX:CompressedClassSpaceSize (デフォルトでは 1G) によって制限されます。 糸
JVM スレッド スタックにも一定量のスペースが必要です。ここでは、61 個のスレッドが 60M のスペースを占有し、各スレッドのデフォルトのスタック サイズは約 1M です。スタック サイズは -Xss パラメータによって制御されます。 コードキャッシュ
コード キャッシュは主に、JIT コンパイラとネイティブ メソッドによってコンパイルされたコードを格納するために使用されます。現在、36M のコードがキャッシュされています。コード キャッシュの容量は、-XX:ReservedCodeCacheSize パラメータを使用して設定できます。 GC GC ガベージ コレクターは、GC 操作をサポートするために、ある程度のメモリ領域も必要とします。 GC によって占有されるスペースは、選択された特定の GC アルゴリズムに関連しています。ここでの GC アルゴリズムは 47M を使用します。他の構成は同じまま、SerialGC に切り替えます。 SerialGC アルゴリズムは 1M のメモリのみを使用することがわかります。これは、SerialGC が単純なデータ構造と少量の計算データを含む単純なシリアル アルゴリズムであるため、メモリ使用量も少ないためです。ただし、単純な GC アルゴリズムはパフォーマンスの低下を招く可能性があるため、選択を行う前にパフォーマンスとメモリパフォーマンスのバランスを取る必要があります。 シンボル
JVM のシンボルには、15M を占めるシンボル テーブルと文字列テーブルが含まれています。 非JVMメモリNMT は JVM 内のメモリのみをカウントでき、一部のメモリは JVM によって管理されません。 JVM 管理メモリに加えて、プログラムはオフヒープ メモリ ByteBuffer.allocateDirect を明示的に要求することもできます。これは -XX:MaxDirectMemorySize パラメータによって制限されます (デフォルトは -Xmx に等しい)。 System.loadLibrary によってロードされた JNI モジュールは、JVM 制御なしでオフヒープ メモリに適用することもできます。 要約すると、Java プロセスのメモリ使用量を正確に推定できるモデルは実際には存在しません。できるだけ多くの要素を考慮するしかありません。これらのメモリ領域の一部は、コード キャッシュやメタスペースなどの JVM パラメータによって容量が制限される場合がありますが、一部のメモリ領域は JVM によって制御されず、特定のアプリケーションのコードに関連しています。 5. オンライン コンテナーではローカル テストよりも多くのメモリが必要なのはなぜですか?同じコードをオンライン コンテナーで実行すると、ローカルで実行するよりも常に多くのメモリが消費され、OOM が発生する可能性がある理由について、ユーザーからよく報告されます。考えられる状況は次のとおりです。 コンテナ対応のJVMバージョンを使用していない一般的な物理マシンまたは仮想マシンでは、-Xmx パラメータが設定されていない場合、JVM は一般的な場所 (Linux の /proc ディレクトリなど) から使用できる最大メモリ量を検索し、ホストの最大メモリの 1/4 をデフォルトの JVM 最大ヒープ メモリとして使用します。初期の JVM バージョンはコンテナに適合していませんでした。コンテナ内で実行する場合、JVM の最大ヒープはホスト メモリの 1/4 に設定されていました。一般的なクラスター ノードのホスト メモリは、ローカル開発マシンのホスト メモリよりもはるかに大きくなります。コンテナ内の Java プロセスのヒープ領域が大きいほど、消費するメモリも多くなります。同時に、コンテナは Cgroup リソース制限の対象となります。コンテナプロセスグループのメモリ使用量が Cgroup 制限を超えると、OOM になります。このため、OpenJDK 8u191 以降では、デフォルトで有効になっている UseContainerSupport パラメータが導入され、コンテナ内の JVM がコンテナのメモリ制限を認識し、Cgroup メモリ制限の 1/4 に応じて最大ヒープ メモリを設定できるようになりました。 オンラインサービスはより多くのメモリを消費する外部にサービスを提供するビジネスでは、新しいオブジェクトの作成や実行スレッドの開始など、よりアクティブなメモリ割り当てアクションが発生することがよくあります。これらの操作にはメモリ領域の割り当てが必要となるため、オンライン ビジネスでは多くのメモリが消費されることがよくあります。トラフィックのピークが増えると、消費されるメモリも増えます。そのため、サービス品質を確保するためには、自社の業務トラフィックに応じてアプリケーションメモリ構成を適宜拡張する必要があります。 6. クラウドネイティブJavaアプリケーションのメモリ構成に関する推奨事項
|
<<: 高帯域幅、低遅延、高可用性を備えたJigoo Technologyは、オーディオおよびビデオ分野で高品質のネットワークを構築します。
分散技術の発展の歴史を見ると、分散とは実際には、単一のコンピュータが複雑で大規模なデータやタスクを処...
カリフォルニア州サニーベール、2009 年 6 月 1 日 – AMD は本日、2 ウェイ、4 ウェ...
ウェブページの包含の問題1. 自分のウェブサイト(独立したウェブサイトまたはブログ)を Baidu ...
最近、多くの人がWeiboマーケティングを行っていますが、結果は満足できるものではありません。Wei...
現在、入札チュートリアルに関する情報は数多くありますが、そのほとんどは Baidu アカウントの最適...
ご清聴ありがとうございます。この二日間、ウェブサイトが開けない理由を説明させてください。あるウェブサ...
著者は、迅速な最適化のヒントに関する多くの記事を読んで、深く感銘を受けました。著者は、迅速な最適化は...
21世紀のインターネットの急速な発展は、インターネットユーザーの数の劇的な増加と一致しています。より...
インターネットの発展はますます細分化に向かっています。ローカル フォーラムも細分化された産業の 1 ...
まず最初に、真面目なことを言わせてください。以下の内容は初心者がブラックハット原則を学ぶためのもので...
ブログやWeibo(この記事の「Weibo」は、Sina WeiboやTwitterなどのWeibo...
2012年もSEOは引き続き人気が高まり、中小企業にとってSEOが激戦区になることが予想されます。 ...
[51CTO.com クイック翻訳] 今日のハイブリッドクラウド管理に対する強い需要を受けて、クラウ...
筆者はインターネット業界で4年間SEOに携わっており、その間に百度で大小さまざまな調整を経験してきま...
ページの最適化は、Web ページの命名、Web ページのタグ、タイトル、Web ページのコンテンツな...