CPU+ディスク+メモリ+ネットワーク+GCを含むJAVAオンライントラブルシューティングルーチン

1.CPU

一般的に言えば、最初に CPU の問題のトラブルシューティングを行います。多くの場合、CPU 例外はより適切に配置されます。理由には、ビジネス ロジックの問題 (無限ループ)、頻繁な gc、および過剰なコンテキストの切り替えが含まれます。最も一般的なのはビジネス ロジック (またはフレームワーク ロジック) が原因であることが多く、jstack を使用して、対応するスタックの状況を分析できます。

1.1 jstack を使用して CPU の問題を分析する

最初に ps コマンドを使用して、対応するプロセスの pid を見つけます (ターゲット プロセスが複数ある場合は、top を使用してどれがより多くを占めるかを確認できます)。

次に、top -H -p pidを使用して、CPU 使用率が比較的高いスレッドを見つけます。

次に、最も高い占有 pid を 16 進数に変換してprintf '%x\n' pidnid を取得します。

次に、対応するスタック情報を jstack で直接見つけますjstack pid |grep 'nid' -C5 –color

nid 0x42 のスタック情報が見つかったので、それを注意深く分析するだけでよいことがわかります。

もちろん、jstack ファイル全体を分析する方が一般的で、通常はBLOCKEDは言うまでもなくWAITINGTIMED_WAITINGの部分により注意を払います。

cat jstack.log | grep "java.lang.Thread.State" | sort -nr | uniq -cjstackの全体的な状態はコマンドで把握できますが、WAITINGなどが多すぎる場合は問題があると考えられます。

1.2 頻繁な GC

もちろん、引き続き jstack を使用して問題を分析しますが、最初に gc の頻度が高すぎるかどうかを判断し、jstat -gc pid 1000コマンドを使用して gc 生成の変化を観察することができます。

1000 はサンプリング間隔 (ms) を表し、S0C/S1C、S0U/S1U、EC/EU、OC/OU、および MC/MU は、それぞれ 2 つの Survivor 領域、Eden 領域、古い世代、およびメタデータの容量と使用量を表します。エリア。YGC/YGT、FGC/FGCT、および GCT は、YoungGc と FullGc の消費時間、回数、合計消費時間を表します。gc の方が頻度が高いことがわかった場合は、gc についてさらに分析を行います。

1.3 コンテキストの切り替え

コンテキストの問題が頻繁に発生する場合は、vmstat コマンドを使用して表示できます。

cs (コンテキスト スイッチ) 列は、コンテキスト スイッチの数を表します。

特定の pid を監視する場合は、pidstat -w pidコマンドを使用できます。cswch と nvcswch は、自発的および非自発的な切り替えを表します。

2.ディスク 

ディスクの問題は、CPU と同じくらい基本的なものです。まず、ディスク容量に関しては、直接df -hlを使用してファイル システムのステータスを表示します。

多くの場合、ディスクの問題はパフォーマンスの問題です。iostatiostat -d -k -xで分析できます

最後の列 %util では、各ディスクの書き込みレベルを確認できます。rrqpm/s と wrqm/s はそれぞれ読み取り速度と書き込み速度を示しており、通常、問題のある特定のディスクを特定するのに役立ちます。

また、どのプロセスが読み書きを行っているかを知る必要がありますが、一般的に開発者はそれをよく知っているか、iotop コマンドを使用してファイルの読み書きのソースを突き止めます。

しかし、ここで得られるのは tid です。これを pid に変換する必要があります。これは、readlink で確認できます。

コマンド形式: pidreadlink -f /proc/*/task/tid/../..

pid を見つけた後、プロセスcat /proc/pid/ioの特定の読み取りと書き込みを確認できます。

lsof コマンドを使用して、特定のファイルの読み取りおよび書き込み条件を判別することもできます lsof -p pid

3.メモリー

メモリの問題のトラブルシューティングは、CPU よりも面倒であり、より多くのシナリオがあります。主に、OOM、GC の問題、およびオフヒープ メモリが含まれます。一般的に言えば、最初に free コマンドを使用して、メモリのさまざまな状態を確認します。

3.1 ヒープメモリ

メモリの問題のほとんどは、ヒープ メモリの問題でもあります。外観は主に OOM と StackOverflow に分けられます。

3.1.1 OOM

JMV、OOM でのメモリ不足は、次のカテゴリに大別できます。

1.Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

これは、Javaスタックをスレッドに割り当てるための十分なメモリ空間がないことを意味します.基本的には、シャットダウンを忘れるなど、スレッドプールのコードに問題があるため、まずjstackまたはjmapを使用してコードレベルから問題を探す必要があります. . すべてが正常であれば、JVM は Xss を指定することでシングル スレッド スタックのサイズを減らすことができます。

さらに、システム レベルでは、/etc/security/limits.confnofile と nproc を変更することで、スレッドの OS 制限を増やすことができます。

 

2.Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

これは、ヒープのメモリ使用量が -Xmx によって設定された最大値に達したことを意味します。これは、最も一般的な OOM エラーです。解決策は、最初にコード内でそれを見つけ、メモリ リークがあることを疑い、jstack と jmap を使用して問題を特定することです。正常であれば、Xmx の値を調整してメモリを拡張する必要があります。

3.Caused by: java.lang.OutOfMemoryError: Meta space

これは、メタデータ領域のメモリ使用量が XX:MaxMetaspaceSize で設定された最大値に達したことを意味します. トラブルシューティングの考え方は上記と一致しています. パラメータは XX:MaxPermSize を介して調整できます (1.8 より前のパーマネント ジェネレーションは言うまでもありません)。

3.1.2 スタック オーバーフロー

スタック メモリ オーバーフロー、これはよく見られます。

Exception in thread "main" java.lang.StackOverflowError

これは、スレッドスタックが必要とするメモリが Xss の値よりも大きいことを意味し、これも最初にチェックされます. Xss を介してパラメータを調整しますが、調整が大きすぎると OOM が発生する可能性があります.

3.1.3 JMAP を使用してコードのメモリ リークを特定する

OOM と StackOverflow に関する上記のコードのトラブルシューティングでは、通常、

jmap -dump:format=b,file=filename pidダンプ ファイルをエクスポートする

分析のために、mat (Eclipse メモリ分析ツール) を介してダンプ ファイルをインポートします。通常、メモリ リークのLeak Suspectsを直接選択でき、mat はメモリ リークの提案を提供します。

または、Top Consumers を選択して、最大のオブジェクト レポートを表示します。スレッドに関する質問は、スレッドの概要を選択して分析できます。さらに、Histogram クラスの概要を選択して、自分でゆっくりと分析したり、関連するチュートリアルを mat で検索したりできます。

日常の開発では、コード メモリ リークは比較的一般的であり、隠れているため、開発者は詳細に注意を払う必要があります。たとえば、毎回新しいオブジェクトが要求され、オブジェクトの作成が何度も繰り返される、ファイル ストリーム操作が実行されるが正しく閉じられない、gc を手動で不適切にトリガーする、ByteBuffer キャッシュの割り当てが不合理であるなどの理由で、コード OOM が発生します。

一方、起動パラメータで指定して、-XX:+HeapDumpOnOutOfMemoryErrorOOM 時にダンプ ファイルを保存できます。

3.1.4 GC の問題とスレッド

CPU に影響を与えることに加えて、gc の問題はメモリにも影響を与えます。トラブルシューティングのアイデアは同じです。一般的に、jstat は、youngGC や fullGC の回数が多すぎないか、EU や OU などの指標の成長に異常がないかなど、世代交代を確認するために使用されます。

スレッドが多すぎて時間内に gc にならない場合も oom が発生し、そのほとんどは前述のように新しいネイティブ スレッドを作成できません。jstack によるダンプ ファイルの詳細な分析に加えて、通常は、最初にpstreee -p pid |wc -lを使用してスレッド全体を調べます

または直接 /proc/pid/task の数を表示して、スレッドの数です。

3.2 オフヒープメモリ

オフヒープ メモリ オーバーフローが発生した場合は、非常に残念です。まず、オフヒープメモリオーバーフローの性能は、物理常駐メモリが急激に増大することです.エラーが報告される場合は、使用方法に依存します.Nettyの使用が原因である場合、OutOfDirectMemoryErrorエラーが表示される場合があります.エラーログ直接DirectByteBufferの場合は報告されますOutOfMemoryError: Direct buffer memory

ヒープ外メモリ オーバーフローは、NIO の使用に関連していることがよくあります. 一般に、最初にpmap . ここで、一定期間後にコマンドを再度実行して、メモリの増加を確認したり、通常のマシンと比較して疑わしいメモリ セグメントがどこにあるかを確認したりできます。

疑わしいメモリ ターミナルがあると判断した場合は、gdb で分析する必要があります. gdb --batch --pid {pid} -ex "dump メモリ ファイル名.dump {メモリ開始アドレス} {メモリ開始アドレス + メモリ ブロック サイズ}"

ダンプファイルを取得した後、hexdump を使用して hexdump -C filename | less で表示できますが、表示されるファイルのほとんどはバイナリ文字化けです。

NMT は Java7U40 で導入された HotSpot の新機能で、jcmd コマンドを使用して具体的なメモリ構成を確認できます。起動パラメータに -XX:NativeMemoryTracking=summary または を 追加する必要があります-XX:NativeMemoryTracking=detail。パフォーマンスがわずかに低下します。

通常、オフヒープ メモリが爆発するまでゆっくりと増加する場合は、最初にベースライン jcmd pid VM.native_memory ベースラインを設定できます。

次に、しばらく待ってメモリの増加を確認し、jcmd pid VM.native_memory detail.diff(summary.diff)を介して概要レベルまたは詳細レベルの差分を実行します。

 jcmd によって分析されたメモリは、ヒープ、スレッド、および gc を含めて非常に詳細であることがわかります (したがって、上記の他のメモリ例外は nmt によって実際に分析できます)。ヒープ. 成長が非常に明白な場合 もしそうなら、問題があります.

詳細レベルでは、次の図に示すように、特定のメモリ セグメントも増加します。

さらに、システム レベルでは、strace コマンドを使用してメモリ割り当てを監視することもできますstrace -f -e "brk,mmap,munmap" -p pid

ここでのメモリ割り当て情報には、主にpidとメモリアドレスが含まれます。

しかし、実際には、上記の操作は特定の問題を特定するのが難しく、エラー ログ スタックを見て、疑わしいオブジェクトを見つけ、その回復メカニズムを把握し、該当するオブジェクトを分析することが重要です。たとえば、DirectByteBuffer がメモリを割り当てる場合、完全な GC または手動の system.gc をリサイクルする必要があります (したがって、-XX:+DisableExplicitGC を使用しないことをお勧めします)。

実際、DirectByteBuffer オブジェクトのメモリを追跡し、jmap -histo:live pid を介して手動で fullGC をトリガーして、ヒープ外のメモリがリサイクルされたかどうかを確認できます。再利用する場合、オフヒープメモリ自体の割り当てが小さすぎる可能性が高く、-XX:MaxDirectMemorySize で調整できます。変化がない場合は、jmap を使用して gc できないオブジェクトと、DirectByteBuffer との参照関係を分析します。

四、GC問題

ヒープ内メモリ リークには常に GC 例外が伴います。ただし、GC の問題はメモリの問題だけでなく、CPU 負荷やネットワークの問題など一連の合併症を引き起こす可能性がありますが、メモリとの関連は比較的深いため、ここでは GC 関連の問題を個別にまとめます。

cpu の章で、jstat を使用して現在の GC 世代の変更情報を取得する方法を紹介しました。多くの場合、GC ログを使用して問題をトラブルシューティングし、それらを起動パラメーターに追加して-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStampsGC ログを有効にします。

一般的な Young GC および Full GC ログの意味は、ここでは繰り返されません。

GC ログによると、適切な薬を処方するために、youngGC と fullGC が頻繁すぎるか、時間がかかりすぎるかを大まかに推測できます。以下で G1 ガベージ コレクタを分析しますが、G1-XX:+UseG1GC を使用することもお勧めします。

4.1 YoungGC が多すぎる

短期間に小さなオブジェクトが多いため、YoungGC が頻繁に発生します.まず、Eden 領域/新世代の設定が小さすぎるかどうかを検討し、-Xmn や -XX:SurvivorRatio などのパラメータ設定を調整して問題を解決できるかどうかを確認します。 . パラメータが正常であるにもかかわらず、若い gc の頻度がまだ高すぎる場合は、Jmap と MAT を使用してダンプ ファイルをさらに確認する必要があります。

4.2youngGC に時間がかかりすぎる

時間がかかりすぎるという問題は、GC ログのどこで時間が費やされているかによって異なります。G1 ログを例にとると、ルート スキャン、オブジェクト コピー、Ref Proc などのステージに焦点を当てることができます。Ref Proc は時間がかかるため、関連オブジェクトの参照には注意が必要です。

ルートスキャンは時間がかかるため、スレッド数や世代間参照に注意してください。Object Copy は、オブジェクトのライフサイクルに注意を払う必要があります。さらに、時間のかかる分析には、水平比較が必要であり、これは他のプロジェクトや通常の期間との比較に時間がかかります。たとえば、図の Root Scanning が通常の期間よりも増加する場合は、開始されたスレッドが多すぎることを意味します。

 
4.3 FullGC のトリガー

G1 では混合 GC が多くなりますが、混合 GC は若い GC と同じ方法で確認できます。通常、fullGC がトリガーされると問題が発生します. G1 は縮退し、シリアル コレクターを使用してガベージ クリーニング作業を完了します. 一時停止時間は 2 番目のレベルに達します。

fullGC の理由には、次のようなものと、パラメーター調整のアイデアが含まれる場合があります。

  • コンカレント フェーズでの失敗: コンカレント マーキング フェーズでは、MixGC の前に古い世代がいっぱいになり、G1 はこの時点でマーキング サイクルを放棄します。この場合、ヒープ サイズを増やすか、同時マーキング スレッドの数を調整する必要がある場合があります -XX:ConcGCThreads。

  • 昇格の失敗: GC 中にオブジェクトを存続/昇格させるための十分なメモリがないため、フル GC がトリガーされます。このとき、-XX:G1ReservePercent を使用して予約メモリの割合を増やし、-XX:InitiatingHeapOccupancyPercent を減らして事前にマーキングを開始し、-XX:ConcGCThreads を使用してマーキング スレッドの数を増やすことも可能です。

  • ラージ オブジェクトの割り当ての失敗: ラージ オブジェクトが割り当てに適した領域スペースを見つけることができず、fullGC が実行されます。この場合、メモリを増やすか、-XX:G1HeapRegionSize を増やすことができます。

  • プログラムは積極的に System.gc() を実行します。

さらに、起動パラメーターで -XX:HeapDumpPath=/xxx/dump.hprof を構成して fullGC 関連のファイルをダンプし、jinfo を使用して gc の前後にダンプを実行できます。

jinfo -flag +HeapDumpBeforeFullGC pid 
jinfo -flag +HeapDumpAfterFullGC pid

 このようにして得られた 2 つのダンプ ファイルを比較した後、主に gc によってドロップされた問題のあるオブジェクトに焦点を当てて、問題を突き止めます。

5. ネットワーク

ネットワーク レベルに関連する問題は一般的により複雑で、多くのシナリオと困難なポジショニングがあり、ほとんどの開発者にとって悪夢となっており、最も複雑なはずです。ここではいくつかの例を示し、tcp 層、アプリケーション層、およびツールの使用の観点から説明します。

5.1 タイムアウト

タイムアウト エラーのほとんどはアプリケーション レベルで発生するため、この記事では概念の理解に重点を置きます。タイムアウトは、接続タイムアウトと読み取り/書き込みタイムアウトに大別できます。接続プールを使用する一部のクライアント フレームワークには、接続タイムアウトとアイドル接続のクリーンアップ タイムアウトもあります。

  • 読み取りと書き込みがタイムアウトしました。readTimeout/writeTimeout、一部のフレームワークは so_timeout または socketTimeout と呼ばれ、どちらもデータの読み取りと書き込みのタイムアウトを指します。ここでのタイムアウトのほとんどは、論理タイムアウトを指していることに注意してください。soa のタイムアウトは、読み取りタイムアウトも参照します。読み取りおよび書き込みのタイムアウトは、通常、クライアントに対してのみ設定されます。

  • 接続がタイムアウトしました。connectionTimeout、クライアントは通常、サーバーとの接続を確立するための最大時間を参照します。サーバー側の connectionTimeout は少し異なります. Jetty はアイドル状態の接続クリーニング時間を示し、tomcat は接続メンテナンスの最大時間を示します.

  • 他の。接続取得タイムアウト connectionAcquireTimeout とアイドル接続クリーンアップ タイムアウト idleConnectionTimeout を含みます。主に、接続プールまたはキューを使用するクライアントまたはサーバー フレームワークに使用されます。

各種タイムアウトを設定する際に確認しなければならないのは、接続が正常に終了するように、クライアント側のタイムアウトをサーバーのタイムアウト時間よりも可能な限り小さく保つことです。

実際の開発で最も気をつけなければならないのは、インターフェイスの読み取りと書き込みがタイムアウトになることです。

適切なインターフェイス タイムアウトを設定する方法が問題です。インターフェースのタイムアウト設定が長すぎると、サーバーの tcp 接続を占有しすぎる可能性があります。また、インターフェイスの設定が短すぎると、インターフェイスが頻繁にタイムアウトになります。

サーバー インターフェイスが明らかに rt を下げているのに、クライアントが常にタイムアウトすることも別の問題です。この問題は、実際には非常に単純です. クライアントからサーバーへのリンクには、ネットワーク送信、キューイング、およびサービス処理が含まれます. 各リンクには時間がかかる場合があります.

5.2 TCP キューのオーバーフロー

tcp キュー オーバーフローは比較的低レベルのエラーであり、タイムアウトや rst などのより表面的なエラーを引き起こす可能性があります。したがって、エラーもより微妙なので、個別に説明しましょう。

上の図に示すように、syns キュー (半接続キュー) と accept キュー (全接続キュー) の 2 つのキューがあります。サーバーがクライアントのsynを受信した後、メッセージをsynsキューに入れ、syn + ackをクライアントに返信し、サーバーはクライアントのackを受信し、この時点でacceptキューがいっぱいでない場合は取り出しますsyns キューからの一時ストレージ 情報を受け入れキューに入れます。それ以外の場合は、tcp_abort_on_overflow の指示に従います。

tcp_abort_on_overflow 0 は、スリーウェイ ハンドシェイクの 3 番目のステップで受け入れキューがいっぱいになった場合、サーバーがクライアントから送信された ack を破棄することを意味します。tcp_abort_on_overflow 1 は、3 番目のステップで完全な接続キューがいっぱいになった場合、サーバーが最初のパケットをクライアントに送信することを意味し、ハンドシェイク プロセスと接続が廃止されたことを示します。ログをピアリングします。

実際の開発では、tcp キューのオーバーフローをすばやく特定するにはどうすればよいでしょうか。

netstat コマンド、実行netstat -s | egrep "listen|LISTEN"

上の図に示すように、overflowed はフル接続キュー オーバーフローの数を示し、sockets drop は半接続キュー オーバーフローの数を示します。

ss コマンド、ss -lnt を実行

上記のように、Send-Q は、3 列目のリッスン ポートで完全に接続されたキューの最大数が 5 であることを示し、Recv-Q の 1 列目は、完全に接続されたキューが現在どれだけ使用されているかを示します。

次に、完全な接続と半接続のキュー サイズを設定する方法を見てみましょう。

完全に接続されたキューのサイズは、min(backlog, somaxconn) によって異なります。バックログはソケットの作成時に渡され、somaxconn は OS レベルのシステム パラメータです。準結合キューのサイズは、max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog) によって異なります。

日々の開発ではサーブレットコンテナをサーバーとして利用することが多いため、コンテナの接続キューのサイズに注意を払う必要がある場合があります。バックログは、tomcat では acceptCount と呼ばれ、jetty では acceptQueueSize と呼ばれます。

5.3 RST 例外

RST パケットは接続のリセットを意味し、不要な接続を閉じるために使用されますが、通常は異常なシャットダウンを意味し、4 つの手を振るのとは異なります。

実際の開発では、RST パッケージが原因であるピア エラーによる接続のリセット/接続のリセットがよく見られます。

▶ ポートが存在しない

接続を確立するための SYN 要求が存在しないポートに送信された場合、サーバーは、このポートがないことを検出すると、接続を終了するために RST メッセージを直接返します。

▶ 積極的に FIN を置き換えて接続を終了する

一般的に言えば、通常の接続の終了は FIN メッセージで実現する必要がありますが、接続が直接終了することを示す FIN の代わりに RST メッセージを使用することもできます。実際の開発では、SO_LINGER の値を設定して制御することができます.これは、TIMED_WAIT をスキップして対話効率を向上させるために意図的に行われることがよくあります.アイドルでない場合は注意して使用してください.

▶ クライアントまたはサーバーの一方の側で例外が発生し、方向が他方の側に RST を送信して、接続のクローズを通知します

RST パケットを送信するために前述した tcp キュー オーバーフローは、実際にはこのカテゴリに属します。これは多くの場合、何らかの理由で一方がリクエスト接続を正常に処理できなくなり (たとえば、プログラムがクラッシュした、キューがいっぱいになった)、他方に接続を閉じるように伝えます。

▶ 受信した TCP メッセージが既知の TCP 接続にない

たとえば、ネットワークの状態が悪いために一方のマシンが TCP メッセージを失った場合、相手側は接続を閉じ、欠落している TCP メッセージを久しぶりに受信しますが、対応する TCP 接続が存在しないため、直接送信します。新しい接続を開くための RST パケット。

▶一方が他方からの確認メッセージを長期間受信せず、一定時間または一定回数の再送信後にRSTメッセージを送信する

これらの多くはネットワーク環境にも関係しており、ネットワーク環境が悪いと RST パケットが増える可能性があります。

前に、RST パケットが多すぎるとプログラムがエラーを報告すると言いました. クローズされた接続での読み取り操作は接続のリセットを報告し、クローズされた接続での書き込み操作はピアによる接続のリセットを報告します. 通常、パイプライン レベルでのエラーである壊れたパイプ エラーも表示される場合があります。これは、閉じたパイプラインへの読み取りと書き込みが、多くの場合、RST を受信して​​接続リセット エラーを報告した後、データグラムの読み取りと書き込みを続行するエラーであることを示しています。 glibc のソース コードのコメントでも紹介されています。

トラブルシューティング時に RST パケットの存在を確認するにはどうすればよいですか? もちろん、tcpdump コマンドを使用してパケットをキャプチャし、wireshark を使用して簡単な分析を行います。tcpdump -i en0 tcp -w xxx.cap, en0 は監視ネットワーク カードを示します。

次に、wireshark を介してキャプチャされたパケットを開くと、次の図が表示されます。赤いものは RST パケットを表します。

TIME_WAITとCLOSE_WAIT

TIME_WAIT と CLOSE_WAIT の意味は誰もが知っていると思います。

オンラインの場合、コマンドを直接使用して、netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'time-wait と close_wait の数を表示できます

ss コマンドを使用する方が高速になりますss -ant | awk '{++S[$1]} END {for(a in S) print a, S[a]}'

TIME_WAIT

time_wait の存在は、失われたデータ パケットが後続の接続によって多重化されるためであり、2 つ目は、2MSL の時間範囲内で正常に接続を閉じるためです。その存在により、実際には RST パケットの発生が大幅に減少します。

過度の time_wait は、短い接続が頻繁に発生するシナリオで発生する可能性が高くなります。この場合、サーバー側でいくつかのカーネル パラメータの調整を行うことができます。

#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 1

もちろん、NAT 環境ではタイム スタンプが間違っているためにデータ パケットが拒否されることを忘れてはなりません.別の方法として、tcp_max_tw_buckets を減らすこともできます。バケット テーブルのオーバーフローが報告されるのを待ちます。間違っています。

CLOSE_WAIT

close_wait は、多くの場合、アプリケーション プログラムに問題があり、ACK の後に再度 FIN メッセージが送信されないことが原因です。close_wait の確率は time_wait の確率よりもさらに高く、結果はより深刻です。多くの場合、特定の場所がブロックされ、接続が正常に閉じられず、徐々にすべてのスレッドが消費されます。

この種の問題を見つけたい場合は、jstack を使用してスレッド スタックを分析し、問題を解決するのが最善の方法です. 詳細については、上記の章を参照してください. これはほんの一例です。

開発者は、アプリケーションがオンラインになってからハングアップするまで CLOSE_WAIT が増加し続けたと言いました. jstack の後、ほとんどのスレッドが countdownlatch.await メソッドでスタックしていたので、疑わしいスタックを見つけました. threading は使用されましたが、それはありませんでした. catch 例外、変更後、例外は、sdk のアップグレード後に頻繁に発生する、見つかっていない最も単純なクラスのみであることがわかりました。

おすすめ

転載: blog.csdn.net/u011487470/article/details/127675102