Linux でのシステム トラブルシューティングの基本ルーチン

一般的なコマンドをまとめます

  1. トップ CPU 使用率の高いプロセスを見つける
  2. ps 対応するプロセスの pid を見つけます。
  3. top -H -p pid CPU 使用率の高いスレッドを検索します
  4. printf '%x\n' pid スレッドの pid を 16 進数に変換して nid を取得します
  5. jstack pid |grep 'nid' -C5 –color 分析のために jstack 内の対応するスタック情報を検索します。
  6. cat jstack.log | grep “java.lang.Thread.State” | sort -nr | uniq -c jstack を包括的に把握し、waiting や timed_waiting などのスレッドの状態に注意を払う
  7. jstat -gc pid 1000 で gc 世代の変化を観察します。
  8. vmstat l 頻繁に発生するコンテキストの問題を表示する
  9. pidstat -w pid モニター固有の pid
  10. ディスク
  11. df -hl ディスク ファイル システムのステータスを表示します
  12. iostatiostat -d -k -x ディスクの読み取りおよび書き込み速度を分析し、問題のあるディスクを特定します。
  13. iotop スレッドの読み取りおよび書き込み ID を表示、readlink -f /proc/*/task/tid/…/… プロセス PID を検索
  14. cat /proc/pid/io プロセスの特定の読み取りおよび書き込み条件を表示します。
  15. lsof -p pid 特定のファイルの読み取りおよび書き込み条件を決定します。
  16. メモリ
  17. free メモリの状態を確認する
  18. jstackとjmapを確認したところ問題はありませんでした
  19. jvm-設定-Xss
  20. -Xms
  21. XX:MaxPermSize
  22. JMAPjmap -dump:format=b,file=filename pid エクスポート ダンプ ファイル

  23. oom 時にダンプ ファイルを保存するには、起動パラメータに -XX:+ HeapDumpOnOutOfMemoryError を指定します。
  24. pstreee -p pid |wc -l または ls -l /proc/pid/task | ws -l を使用してスレッドの全体数を表示します
  25. pmap -x pid | sort -rn -k3 | head -30 プロセスのカウントダウンに対応する上位 30 のメモリ セグメントを表示します
  26. strace -f -e “brk,mmap,munmap” -p pid メモリ割り当ての監視

オリジナル

オンライン障害には主に CPU、ディスク、メモリ、ネットワークの問題が含まれますが、ほとんどの障害には複数のレベルの問題が含まれる場合があるため、トラブルシューティングの際には 4 つの側面を順番に確認するようにしてください。

同時に、jstack や jmap などのツールは問題の 1 つの側面に限定されるわけではなく、基本的に問題は df、フリー、トップ 3 連続、その後 jstack と jmap が順番にサーブし、特定の問題を分析することができます。詳細。

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

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

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

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

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

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

もちろん、jstack ファイル全体を分析することの方が一般的ですが、通常は BLOCKED は言うまでもなく、WAITING と TIMED_WAITING の部分に注目します。cat jstack.log | grep "java.lang.Thread.State" | sort -nr | uniq -c コマンドを使用すると、jstack の全体的な状態を把握できます。WAITING などが多すぎる場合は、おそらく問題があります。

もちろん、引き続き 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 についてさらに分析を行ってください。

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

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

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

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

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

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

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

しかし、ここで得られるのは tid です。これを pid に変換したいのですが、readlink -f /proc/*/task/tid/../.... を通じて pid を見つけることができます。

pid を見つけたら、プロセス cat /proc/pid/io の具体的な読み取りと書き込みを確認できます。

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

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

メモリの問題のほとんどは、ヒープ メモリの問題でもあります。見た目は大きくOOMとStackOverflowに分かれます。

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

スレッド「メイン」java.lang.OutOfMemoryError での例外: 新しいネイティブ スレッドを作成できません

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

さらに、システム レベルで、

/etc/security/limits.confnofile と nproc で OS のスレッド制限を増やす

スレッド「メイン」java.lang.OutOfMemoryError での例外: Java ヒープ スペース

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

原因: java.lang.OutOfMemoryError: メタスペース

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

スタック メモリ オーバーフロー、これはよく目にしたことがあるでしょう。

スレッド「メイン」java.lang.StackOverflowError での例外

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

前述の OOM と StackOverflow のコードのトラブルシューティングでは、通常、JMAPjmap -dump:format=b,file=filename pid を使用してダンプ ファイルをエクスポートします。

分析のために mat (Eclipse メモリ分析ツール) を介してダンプ ファイルをインポートします。一般に、メモリ リークのリークの疑いを直接選択でき、mat はメモリ リークの提案を提供します。あるいは、「上位コンシューマー」を選択して、最大のオブジェクトのレポートを表示します。スレッドの概要を選択すると、スレッドに関連する質問を分析できます。さらに、Histogram クラスの概要を選択して自分でゆっくり分析し、マット上で関連するチュートリアルを検索することができます。

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

一方、起動パラメータに -XX:+ を指定することもできます。

OOM 時にダンプ ファイルを保存するには HeapDumpOnOutOfMemoryError。

gc の問題は CPU に影響するだけでなく、メモリにも影響します。トラブルシューティングの考え方は同じです。一般的に jstat は、youngGC や fullGC の時間が多すぎないか、EU や OU などの指標の伸びが異常ではないかなど、世代交代を確認するために使用されます。

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

または、スレッドの数である /proc/pid/task の数を直接表示してください。

オフヒープ メモリ オーバーフローが発生した場合は、非常に残念です。まず、オフヒープ メモリ オーバーフローのパフォーマンスは、物理的な常駐メモリが急速に増加することです。エラーが報告されるかどうかは、使用方法によって異なります。Netty の使用が原因の場合は、OutOfDirectMemoryError エラーが表示されることがあります。エラー ログ。直接 DirectByteBuffer の場合、OutOfMemoryError が報告されます: ダイレクト バッファ メモリ。

ヒープ外のメモリ オーバーフローは、NIO の使用に関連することがよくあります。一般に、最初に pmap pmap -x pid | sort -rn -k3 | head -30 を通じてプロセスによって占有されているメモリを確認します。逆順で pid に対応する 30 大きなメモリ セグメント。ここでは、一定期間後にコマンドを再度実行してメモリの増加を確認したり、通常のマシンと比較して疑わしいメモリ セグメントがどこにあるかを確認したりできます。

不審なメモリ端子があると判断した場合は、gdb --batch --pid {pid} -ex "ダンプメモリファイル名.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_memorydetail.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 関連の問題について個別にまとめます。

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

一般的なヤング GC ログとフル GC ログの意味については、ここでは繰り返しません。

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

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

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

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

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 の前後にダンプを実行できます。


 
 
  
  
  1. jinfo -flag +HeapDumpBeforeFullGC pid
  2. jinfo -flag +HeapDumpAfterFullGC pid

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

通信網

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

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

  • 読み取りおよび書き込みタイムアウト

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

  • 接続がタイムアウトしました

connectionTimeout は、通常、クライアントがサーバーとの接続を確立するまでの最大時間を指します。サーバー側の connectionTimeout は少し異なり、Jetty はアイドル接続のクリーニング時間を示し、tomcat は接続維持の最大時間を示します。

  • 他の

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

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

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

適切なインターフェースのタイムアウトをどのように設定するかが問題です。インターフェイスのタイムアウト設定が長すぎると、サーバーの TCP 接続を過剰に占有する可能性があります。また、インターフェイスの設定が短すぎる場合、インターフェイスは頻繁にタイムアウトになります。

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

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

上の図に示すように、syns キュー (半接続キュー) と accept キュー (完全接続キュー) の 2 つのキューがあります。スリーウェイ ハンドシェイク。サーバーがクライアントの syn を受信した後、メッセージを syns キューに入れ、クライアントに syn+ack を返信します。サーバーはクライアントの ack を受信します。この時点で受け入れキューがいっぱいでない場合は、取り出します。 syns キューからの一時ストレージ。情報を accept キューに入れます。それ以外の場合は、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 は完全接続キューのオーバーフローの数を示し、socket Drops は半接続キューのオーバーフローの数を示します。

上で見られるように、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 と呼ばれます。

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

実際の開発では、RST パッケージに起因する接続リセット / ピアによる接続リセットエラーが頻繁に発生します。

接続を確立するための SYN リクエストが存在しないポートに送信された場合、サーバーはそのポートがないことが判明すると、直接 RST メッセージを返して接続を終了します。

一般に、通常の接続の終了は 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 が何を意味するかは誰もが知っていると思います。

オンラインの場合、コマンド netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' を直接使用して、時間待機を表示できます。と 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 を減らすこともできます。この値を超える time_wait は強制終了されますが、これによっても時間がかかります。バケット テーブルのオーバーフローが報告されるまで待ちます。間違っています。

CLOSE_WAIT

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

この種の問題を特定したい場合は、jstack を介してスレッド スタックを分析して問題のトラブルシューティングを行うのが最善です。詳細については、上記の章を参照してください。ここに挙げるのはほんの一例です。

開発者は、アプリケーションがオンラインになってからハングアップするまで CLOSE_WAIT が増加し続けると言いました。jstack の後、ほとんどのスレッドが countdownlatch.await メソッドでスタックしているため、疑わしいスタックを見つけました。開発者を探した後、マルチスレッド化が使用されていましたが、使用されていなかった例外をキャッチ、修正後、SDK のアップグレード後によく発生する、例外が見つからない最も単純なクラスのみであることがわかりました。

元のリンク:

https://www.toutiao.com/article/6868136002486010371/?channel=&source=search_tab

おすすめ

転載: blog.csdn.net/qq_36256590/article/details/132448345