Java 回線での CPU およびメモリの使用量が多い問題のトラブルシューティング手順

01 はじめに

1 年近く Java 開発に携わっているプログラマとして、私はオンラインで特定のモジュールのポッドによって発行される CPU およびメモリのアラームによく遭遇します。これらの問題により、システムの応答が遅くなり、サービスが利用できなくなることもあります。一般に、ポッドのリソースを再起動するか増やすか、ポッドの数を増やすことで問題を一時的に解決できますが、これは一時的な解決策であり、根本的な原因ではありません。では、アラームの原因を迅速に特定するにはどうすればよいでしょうか? 以下に一般的な処理の考え方をまとめます。

一般に、Java プログラムの CPU とメモリが高くなる理由は 2 つあります。

  • コード内の特定の場所で大量のデータが読み取られるため、システム メモリが枯渇し、フル GC の回数が多すぎてシステムが遅くなります。

  • コード内には比較的 CPU を集中的に使用する操作が含まれているため、CPU 使用率が高くなり、システム動作が遅くなります。

  • コード内の特定の位置にブロック操作があるため、全体として関数呼び出しに時間がかかりますが、その発生は比較的ランダムです。

  • 特定のスレッドが何らかの理由で待ち状態になり、この時点では機能全体が利用できませんが、再現することはできません。

  • ロックの不適切な使用により、複数のスレッドがデッドロック状態になり、システム全体が遅くなります。

最初の 2 つの状況はより頻繁に発生し、システムが使用不能になる可能性があります。一方、後の 3 つの状況は、特定の機能の実行が遅くなりますが、システムが使用不能になることはありません。

最初のケースでは、データの全量を確認するためのインターフェイスが一定期間に頻繁に呼び出され、メモリが枯渇して異常な GC が発生するという状況に遭遇しました。原因となる CPU とメモリの使用量の問題を必ず解決してください。 GCは1回。いくつかの具体的なトラブルシューティング手順を以下にまとめます。

02 分析ツール

01 top コマンドで CPU 使用率を表示します。

PID はプロセス番号、COMMAND はそこで実行されるコマンド、Java は探しているアプリケーションです

  • 上: すべてのプロセスの使用状況を表示します

  • top -N num: CPU 使用率が最も高い num 個のプロセスを表示します。

root@8d36124607a0:/# top

top - 14:01:23 up 1 day, 17:54,  1 user,  load average: 0.00, 0.01, 0.05Tasks: 101 total,   1 running, 100 sleeping,   0 stopped,   0 zombie%Cpu(s):  0.8 us,  1.2 sy,  0.0 ni, 98.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 stKiB Mem :  3782864 total,  1477524 free,   329656 used,  1975684 buff/cacheKiB Swap:        0 total,        0 free,        0 used.  3181392 avail Mem
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
  9   root      20   0 1031064  52580  19248 S  90.3 10.4  26:30.37 javacatalina.sh
root@8d36124607a0:/# top -Hp 9

top - 08:31:16 up 30 min,  0 users,  load average: 0.75, 0.59, 0.35Threads:  11 total,   1 running,  10 sleeping,   0 stopped,   0 zombie%Cpu(s):  3.5 us,  0.6 sy,  0.0 ni, 95.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 stKiB Mem:   2046460 total,  1924856 used,   121604 free,    14396 buffersKiB Swap:  1048572 total,        0 used,  1048572 free.  1192532 cached Mem  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
   10 root      20   0 2557160 289824  15872 R 79.3 14.2   0:41.49 java
   11 root      20   0 2557160 289824  15872 S 1.2  14.2   0:06.78 java

CPU 消費量が最も高い PID はスレッド ID である 10 であることがわかります。次のコマンドを使用して、16 進形式に変換します。

root@8d36124607a0:/# printf "%x\n" 10

スレッドで取得される出力は 0xa です。

02 jstack を使用して Java スレッド情報を表示する

  • jstack プロセス ID | grep スレッド ID: スレッド スタック情報を表示し、前の手順の Java スレッド プロセス ID と、CPU 使用率が高いスレッド ID (16 進形式) を入力します。

  • jstack pid >> stack.txt: 今後のすべてのスタック情報を stack.txt に出力します

root@8d36124607a0:/# jstack 9 | grep 0xa

"VM Thread" os_prio=0 tid=0x00007f871806e000 nid=0xa runnable”
 
 

最初の二重引用符はスレッド名です。「VM Thread」の場合は仮想マシンの GC リサイクル スレッドです。「main」の場合は別のスレッドです。その後ろにある実行可能ファイルはスレッドの状態です。

03 jstat を使用して GC 情報を表示する

  • jstat -gcutil プロセス番号の統計間隔 (ミリ秒単位) 統計 (デフォルトは常に統計を意味します)

root@8d36124607a0:/# jstat -gcutil 9 1000 10

  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT  0.00   0.00   0.00  75.07  59.09  59.60   3259    0.919  6517    7.715    8.635
  0.00   0.00   0.00   0.08  59.09  59.60   3306    0.930  6611    7.822    8.752
  0.00   0.00   0.00   0.08  59.09  59.60   3351    0.943  6701    7.924    8.867
  0.00   0.00   0.00   0.08  59.09  59.60   3397    0.955  6793    8.029    8.984
 
 

あるプロセスの GC の継続的な変化を確認し、戻り値の FGC が大きく増え続けていれば Full GC と確定! また、「jmap -heap プロセス ID」を使用して、プロセスのヒープが変化しているかどうかを確認することもできます。プロセスがオーバーフローしそうになっています。特に古い世代では、使用量がフル GC を処理するためのしきい値 (ガベージ コレクターと起動時に設定されたしきい値を参照) に達するのが一般的です。

04 Jmapを使用してメモリを分析する

  • jmap -dump: format=b, file= ファイル名 プロセス ID:

    オフライン分析用にメモリ ダンプ ファイルを生成します。

  • ダンプファイルインターフェース解析ツール:

    IBM HeapAnalyzer、クリックして入力し、ha457.jar のダウンロード リンクを見つけてダウンロードします。

  • java -Xmx4G -jar ha457.jar:

    jar ファイルを実行します。ダンプ ファイルが大きすぎる場合は、-Xmx を使用して最大ヒープ メモリ サイズを設定し、メモリ オーバーフローを防ぐことができます。

ha457.jar の GUI インターフェイスを通じて、さまざまな種類のデータのメモリ使用量、オブジェクト間の参照関係、メモリ リークが発生している可能性のあるオブジェクトを明確に確認できます。

03 原因分析

01 Full GC の回数が多すぎます

比較的、この状況は、特に新機能がリリースされたときに最も発生しやすくなります。Full GC が多い状況では、主に次の 2 つの特徴があります。

  • ライン上の複数のスレッドの CPU が 100% を超えており、jstack コマンドを使用すると、これらのスレッドは主にガベージ コレクション スレッドであることがわかります。

  • jstat コマンドで GC の状況を監視すると、Full GC の数が非常に多く、その数が常に増加していることがわかります。

事前調査: top コマンドと top -Hp コマンドを使用して CPU 使用率が最も高い Java スレッドを検索し、16 進数に変換し、jstack コマンドを使用してスレッド情報を取得し、スレッド名が「VM Thread」ガベージ コレクションであることを確認します。糸。


さらに確認:  jstat -gcutil コマンドを使用して、gc の数と増加を表示します。
さらに分析: jmap -dump コマンドを使用してメモリをダンプし、オフライン分析には ha457.jar を使用します。

  • 大量のオブジェクトを生成し、メモリ オーバーフローが発生する

  • メモリ使用量は高くありませんが、フル GC の数は依然として比較的多く、コード内の System.gc() の手動呼び出しにより GC 回数が多すぎる可能性があります。

02 特定のビジネスロジックの実行時間が長すぎる

Full GC の回数が多すぎる場合、jstack を通じて取得されるスレッド情報は VM Thread と同様のスレッドになり、コード内に時間のかかる計算がある場合、取得されるのは特定のスタック情報になります。糸。

以下は、コード内に時間のかかる計算が含まれており、 CPU の負荷が高すぎるスレッド情報です。

ここで、UserController がリクエストされたとき、Controller は時間のかかる呼び出しを行うため、スレッドの CPU は常に 100% であることがわかります。スタック情報によると、 UserController の 34 行目を直接見つけて、コード内で大量の計算が発生している原因を確認できます

03 デッドロック

デッドロックが発生した場合は、直接プロンプトが表示されます。キーワード: デッドロック。jstack を使用してスレッド情報を出力すると、ビジネス デッドロックの場所が出力されます。

04 Cheng は WAITTING 状態になりました

この種の状況では、これは比較的まれな状況ですが、可能性もあり、特定の「再現不可能性」があるため、調査中にそれを見つけるのは非常に困難です。

何らかの理由でスレッドが WAITING 状態になり、現時点では機能全体が利用できませんが、再現することはできません。jstack は、パーキングによって WAITING 状態でスタックしたスレッドと比較して、毎回 30 秒の間隔で数回クエリを実行します。

スレッドに名前を付けると、ビジネス コードをすぐに見つけることができます。

05 多数のスレッドがランダムにインターフェイスへのアクセスが遅いように見える

この状況の典型的な例としては、特定のインターフェイスへのアクセスに戻るまでに 2 ~ 3 秒かかることがよくあります。

これは、一般的に CPU やメモリをあまり消費しないため、上記の 2 つのトラブルシューティング方法では解決できない、かなり厄介な状況です。

また、このようなインターフェースでは時間のかかる問題が時折発生し、スレッドがアクセスするスタック情報を jstack コマンドで取得しても、どのスレッドが時間のかかる処理を実行しているのか判断できません。作戦のルート。

時折現れるインターフェイスの時間のかかる問題に対する、私たちの位置付けの考え方は基本的に次のとおりです。

まずインターフェイスを見つけて、圧力テスト ツールを通じてアクセスを継続的に増やします。アクセス頻度が非常に高いため、時間がかかるインターフェイスの特定の位置がある場合、最終的にほとんどのスレッドがこのインターフェイスでブロックされます。チョーク ポイント

このようにして、複数のスレッドに同じスタック ログを持たせることで、基本的にインターフェイス内で時間のかかるコードを見つけることができます。

以下は、コード内の時間のかかるブロック操作の圧力テスト ツールを通じて取得されたスレッド スタック ログです。

上記のログから、UserController の 18 行目で複数のスレッドがブロックされていることがわかります。これは、これがブロック ポイントであり、これがインターフェイスが比較的遅い原因であることを示しています。

04 まとめ

1. トラブルシューティングコマンドの概要

  • 上:

    システム プロセスの CPU とメモリの使用状況を表示し、最も多くを占めているプロセス ID を見つけます。

  • トップ -HP プロセス番号:

    プロセス番号のすべてのスレッドの CPU およびメモリ使用量を確認し、最も多くを占めているスレッド ID を見つけます (表示される PID は 10 進数のスレッド番号で、printf "%x\n" のプロセス番号は 16 進数のスレッド番号に変換されます) )

  • jstack プロセス番号 >> stack.txt:

    プロセス番号が属するプロセスのスタック情報をstack.txtに出力

  • jstack プロセス番号 | grep 16 進スレッド番号:

    最初にプロセス番号が属するスレッドのスタック情報を表示し、通常のスレッドと GC スレッド (「VM スレッド」) を区別するためにスレッド名を表示することができます。

  • jstat -gcutil プロセス番号 統計間隔ミリ秒統計 (デフォルトは常に統計を意味します):

    GC の問題が原因である場合は、GC の状況をさらに観察します。

  • jmap -heap プロセス ID:

    詳細なプロセス メモリ使用量情報の表示

  • jmap -dump: format=b, file= ファイル名 プロセス ID:

    さらに分析するために、プロセス メモリ情報をディスクにダンプします。

  • java -Xmx4G -jar ha457.jar:

    ha457.jar を使用してメモリ リークを分析します。

2. 異常事態解決の概要

  • GC の問題:

    top+top -Hp + jstack チェックでは、「VM スレッド」がリソースを消費しすぎていることを確認します。さらに、jmap ツールを使用してメモリ オーバーフローをチェックできます。

  • 業務遂行が遅いという問題:

    top+top -Hp + jstack は、それが共通のビジネス スレッドであることを確認し、どのインターフェイスであるかを確認できます。

  • デッドロック:

    jstack + Java プロセスの印刷スタック情報にはデッドロック情報が含まれています。

  • スレッドは待機状態にあります。

    jstack 情報を数回出力し、待機状態でスタックしているスレッドを比較します。

最後に: 以下の完全なソフトウェア テスト ビデオ学習チュートリアルが整理されてアップロードされており、必要な場合は友人が無料で入手できます。【保证100%免费】

ここに画像の説明を挿入

 これらの資料は、[ソフトウェア テスト] の友人にとって最も包括的で完全な準備倉庫となるはずです。この倉庫は、最も困難な旅を乗り越える何万人ものテスト エンジニアにも同行してきました。あなたにも役立つことを願っています。

おすすめ

転載: blog.csdn.net/wx17343624830/article/details/129635988