CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

同時に、jstackやjmapなどのツールは、問題の1つの側面に限定されず、基本的に、問題はdf、free、topであり、jstackとjmapが順番に提供されます。特定の問題は、詳細に分析できます。

CPU

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

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

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

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

nid 0x42でスタック情報が見つかったことがわかります。次に、それを注意深く分析する必要があります。

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

頻繁なgc

もちろん、引き続きjstackを使用して問題を分析しますが、最初にgcの頻度が高すぎるかどうかを判断し、jstat -gc pid 1000コマンドを使用してgc生成の変化を観察できる場合があります。1000はサンプリング間隔(ms)、S0Cを表します。 / S1C、S0U / S1U、EC / EU、OC / OU、MC / MUは、それぞれ2つのサバイバーエリア、エデンエリア、オールドエイジ、メタデータエリアの容量と使用量を表します。YGC / YGT、FGC / FGCT、およびGCTは、YoungGcおよびFullGcによって消費される時間と頻度および合計時間を表します。gcの頻度が高いことがわかった場合は、gcについてさらに分析を行ってください。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

コンテキストスイッチ

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

ディスク

ディスクの問題はcpuよりも基本的です。1つ目はディスク容量です。直接df-hlを使用してファイルシステムのステータスを表示します。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

最後の列%utilは、各ディスクへの書き込みの程度を確認できます。一方、rrqpm / sとwrqm / sは、それぞれ読み取り速度と書き込み速度を表します。これは、通常、問題のある特定のディスクを見つけるのに役立ちます。

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

しかし、ここで取得したのはtidです。これをpidに変換する必要があります。readlinkからpidreadlink -f / proc / * / task / tid /../ ..を見つけることができます。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

pidを見つけたら、このプロセスの特定の読み取りおよび書き込み条件を確認できますcat / proc / pid / io

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

メモリの問題はCPUよりも厄介であり、より多くのシナリオがあります。主にOOM、GCの問題、オフヒープメモリが含まれます。一般的には、最初にfreeコマンドを使用して、ショットのメモリのさまざまな状態を確認します。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

ヒープメモリ

メモリの問題のほとんどは、依然としてヒープメモリの問題です。主にOOMとStackOverflowに分かれています。

おじさん

JMVのメモリが不足しているため、OOMは大きく次のタイプに分類できます。

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

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

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

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

Caused by: java.lang.OutOfMemoryError: Meta space

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

スタックオーバーフロー

スタックメモリがオーバーフローし、誰もがこれをもっと目にします。

Exception in thread "main" java.lang.StackOverflowError

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

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

OOMとStackOverflowに関する上記のコード調査では、通常、JMAPjmap -dump:format = b、file = filenamepidを使用してダンプファイルをエクスポートします。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

mat(Eclipse Memory Analysis Tools)を使用して、分析用のダンプファイルをインポートします。通常、メモリリークのリークサスペクトを直接選択できます。Matはメモリリークに関する提案を提供します。トップコンシューマーを選択して、最大のオブジェクトレポートを表示することもできます。スレッドに関連する質問は、スレッドの概要を選択することで分析できます。さらに、Histogramクラスの概要を選択して、ゆっくりと自分で分析します。マットで関連するチュートリアルを検索できます。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

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

gcの問題とスレッド

gcの問題は、cpuだけでなくメモリにも影響し、トラブルシューティングのアイデアも一貫しています。一般に、最初にjstatを使用して、youngGCまたはfullGCの時間が多すぎるかどうか、EUやOUなどの指標の成長が異常であるかどうかなどの世代交代を確認します。

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

または、/ proc / pid / taskの数を直接表示すると、スレッドの数になります。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

オフヒープメモリ

ヒープ外のメモリオーバーフローが発生した場合、それは本当に残念です。まず、ヒープ外のメモリオーバーフローは、物理的な常駐メモリの急激な増加によって明らかになります。エラーが報告される場合は、使用方法によって異なります。Nettyの使用が原因である場合は、エラーログにOutOfDirectMemoryErrorエラーが表示されることがあります。DirectByteBufferが直接の場合は、報告されOutOfMemoryError: Direct buffer memoryます。

ヒープ外のメモリオーバーフローは、多くの場合NIOの使用に関連しています。通常、最初にpmapを使用して、プロセスpmap -x pid | sort -rn -k3 | head -30が占めるメモリを表示します。このセクションでは、対応するpidの最初の30を逆の順序で表示します。大容量メモリセグメント。ここで、しばらくしてからコマンドを再度実行して、メモリの増加、または通常のマシンと比較してメモリセグメントが疑わしい場所を確認できます。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

疑わしいメモリ終了があることが確実な場合は、gdb --batch --pid {pid} -ex "dump memory filename.dump {memory start address} {memory start address + memory blocksize}"を使用してgdbを分析する必要があります。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

NMTは、Java7U40によって導入された新しいHotSpot機能です。jcmdコマンドを使用すると、特定のメモリ構成を確認できます。起動パラメータに追加する必要がある -XX:NativeMemoryTracking=summary か、 -XX:NativeMemoryTracking=detailわずかな性能の損失が発生します。

一般に、オフヒープメモリが爆発するまでゆっくりと成長する状況では、ベースラインjcmd pidVM.native_memoryベースラインを最初に設定できます。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

次に、メモリの増加を確認するために一定期間待機し、jcmd pid VM.native_memory detail.diff(summary.diff)を使用して要約または詳細レベルの差分を実行します。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

ただし、上記の操作で特定の問題を特定することは困難です。重要なのは、エラーログスタックを調べ、疑わしいオブジェクトを見つけ、その回復メカニズムを理解してから、対応するオブジェクトを分析することです。たとえば、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:+PrintGCTimeStamps起動パラメーター追加してGCログをオンにします。

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

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

youngGCが多すぎる

多くの場合、youngGCは短周期の小さなオブジェクトです。まず、エデンエリア/セノゾイック設定が小さすぎるかどうかを検討し、-Xmn、-XX:SurvivorRatioなどのパラメータ設定を調整して問題を解決できるかどうかを確認します。パラメータは正常であるが、若いgc頻度がまだ高すぎる場合は、JmapとMATを使用してダンプファイルをさらに調査する必要があります。

youngGCに時間がかかりすぎる

過度に時間がかかるという問題は、GCログのどの部分に時間がかかるかによって異なります。G1ログを例にとると、ルートスキャン、オブジェクトコピー、参照手順、およびその他の段階に焦点を当てることができます。Ref Procは時間がかかるため、関連するオブジェクトの参照に注意してください。

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

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

fullGCをトリガーします

G1はmixedGCに近いですが、mixedGCはyoungGCと同じ方法で調査できます。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によってドロップされた問題オブジェクトにあります。

Javaのソウルメイトを検索し、「バックエンドインタビュー」に返信して、インタビューbook.pdfを送信します。

インターネット

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

タイムアウト

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

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

  • 接続がタイムアウトしました。connectionTimeout、クライアントは通常、サーバーとの接続を確立するための最大時間を参照します。サーバー側のconnectionTimeoutは少し異なります。Jettyはアイドル接続のクリーンアップ時間を表し、tomcatは接続が維持される最大時間を表します。

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

さまざまなタイムアウトを設定するときは、接続が正常に終了するように、クライアントのタイムアウトをサーバーのタイムアウトよりも短くしようとしていることを確認する必要があります。

実際の開発では、インターフェイスの読み取りと書き込みのタイムアウトが最も重要です。

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

サーバーインターフェイスは明らかにrtを減らしますが、クライアントがタイムアウトを維持することは別の問題です。この問題は実際には非常に単純です。クライアントからサーバーへのリンクには、ネットワーク送信、キューイング、およびサービス処理が含まれます。各リンクは時間のかかる原因である可能性があります。

TCPキューオーバーフロー

TCPキューのオーバーフローは比較的低レベルのエラーであり、タイムアウトやrstなどのより表面的なエラーが発生する可能性があります。したがって、エラーはより隠されているので、個別に説明しましょう。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

上の図に示すように、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"

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

上図に示すように、オーバーフローは完全に接続されたキューのオーバーフローの数を示し、ドロップされたソケットは半接続されたキューのオーバーフローの数を示します。

ssコマンド、ss-lntを実行します

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

上記のSend-Qを見ると、3番目の列のリスンポートで完全に接続されたキューの最大数は5であり、最初の列のRecv-Qは、完全に接続されたキューが現在使用している量です。

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

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

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

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は監視ネットワークカードを表します。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

次に、キャプチャしたパケットをwiresharkで開くと、次の図が表示される場合があります。赤い図はRSTパケットを意味します。

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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]}'

CPU、ディスク、メモリ、ネットワークからGCまでのJAVAオンライントラブルシューティングルーチンをワンストップで!

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のアップグレード後に頻繁に表示される、検出されない最も単純なクラスです。

おすすめ

転載: blog.51cto.com/14957073/2542746