TCP Backlog capture は、ポート X で待ち受けている Stratus モジュール上のサーバーアプリケーションが、ポート X に接続しようとするクライアントとの接続を正常に作成できないようにする効果である。一般的な解決策は、サーバーアプリケーションをシャットダウンして再起動することである。この記事では、バックログのキャプチャが発生する理由と、その他のあまり思い切った解決策について説明する。
TCPバックログは、保留中の接続のキュー、つまり、受信したがまだ受け入れられていない接続要求のキューです。OpenVOS 17.1以前のリリースでコンパイルされたアプリケーションや、POSIXライブラリを使用していないOpenVOS 17.1でコンパイルされたアプリケーションでは、アプリケーションが接続要求を受け入れるまで、接続要求は確認応答を送信しません。クライアントは、接続要求パケットを3回から10回の間で、増加する間隔で再送します。正確な詳細は、クライアントのオペレーティングシステムとその設定方法に依存します。ある時点で、サーバーアプリケーションは接続要求を受け入れ、STCP スタックは確認応答を送信します。クライアントがあきらめる前にこの確認応答を受信している限り、接続は完了し、通信を開始できます。
バックログ取得シナリオには、いくつかの条件が必要です。
- サーバーとクライアントの間に一時的なネットワーク障害が発生しています(クライアントとサーバーの間では発生していません)。これにより、クライアントの接続要求をサーバが受信できるようになりますが、サーバの接続確認応答をクライアントが受信できなくなります。
或いは
サーバアプリケーションが何らかの理由で accept 関数の呼び出しが遅れます。
- クライアントは接続要求を送信し続けます。つまり、現在の要求がタイムアウトすると、クライアントは新しい要求を送信します。クライアントのタイムアウト値は、サーバーのタイムアウト値よりも短くなければなりません。
- クライアントとサーバの間のどこかにあるステートフルファイアウォールやその他のデバイスは、クライアントの接続要求をタイムアウトさせ、サーバに応答を返すことなくサーバの接続確認応答を破棄します。このタイムアウト値は、サーバのタイムアウト値よりも短くなければなりません。
残念なことに、この条件の組み合わせは、最初に表示されるかもしれないほど可能性が低くはありません。
これは通常、サーバからのパケットがクライアントに到達できないが、クライアントからのパケットがサーバに到達できるようにするネットワークの停止から始まります。クライアントの接続要求パケットがサーバに到達すると、それはバックログキューに置かれます。サーバアプリケーションが accept コードを呼び出すと、コードはバックログキューから接続要求を取り出し、接続確認応答を送信します。ネットワークが壊れているため、サーバはパケットの確認応答を取得しないため、接続確認応答を再送します。クライアントの TCP スタックも接続確認応答を取得していないため、接続要求を再送します。しばらくすると、クライアントの TCP スタックは諦めて、クライアントアプリケーションは新しいリクエストを送信します。サーバは最初のリクエストに応答し続けます。約1分半後(デフォルトでは)にサーバはタイムアウトし、バックログキューから次のリクエストを取り出します。その間、クライアントは2つ目のリクエストを再送しており、3つ目のリクエストを待っているかもしれません。これらのリクエストもバックログキューにあります。他のクライアントがバックログキューに置かれた接続リクエストを取得することは可能ですが、それが正常に完了するためには、クライアントはサーバのタイムアウトよりも大きいタイムアウトを必要としますが、それに接続リクエストのバックログキュー内の位置を乗算します。一旦ネットワークの停止が修正されると、ステートフルファイアウォールは、サーバのタイムアウトよりも短い時間だけステートを保持するため、もはやステートを持たない接続確認応答を黙ってドロップすることで、停止を永続化させます。
どうやって認識するの?
最初にバックログが一杯になっているか、少なくとも一杯になっています。このコマンドで接続のバックログキューを表示することができます。
analyze_system -request_line (文字列一致バックログ -or syncnt (byte 3Bx) dump_st +)
cbq -full -lport 7654 -faddr 0x) -quit
OpenVOS Release 17.0.2au, analyze_system Release 17.0.2au
現在のプロセスは154、ptep 91CC7100、Noah_Davids.CACです。
同期 6
バックログ5
用意ができました 11:41:19
|
lportはローカルポート番号であり、この場合は7654である。外部アドレス(faddr)の値が0の場合、出力はLISTENINGソケットのみに制限される。バックログの値に1を足した値がsyncntの値に等しい場合、バックログは満杯である。バックログの値に1を足した値がsyncnt値と等しい場合、バックログは満杯である。バックログキューのサイズは、アプリケーションがLISTENING関数を呼び出す際に設定されます。
次に、ネットワークプロトコルのトレースを見る必要があります。トレースを見ると、最後の接続要求が確認されていないことがわかりますが、前の接続要求に対する接続確認があり、それらの確認が何の応答も得られていないことがわかります。
図1のトレースはこれを示しています。各接続にはストリームインデックスが付けられ、色分けもされています。クライアントからの最初の接続要求は時刻0のフレーム1であり、確認応答はフレーム2で送信され、フレーム3で再送信されます。フレーム4は、クライアントが接続要求を再送するものです。STCP はすでに接続確認応答を送信しているので、フレーム 4 はフレーム 5 の TCP 確認応答だけをトリガします。フレーム 6 と 7 は再送された接続確認応答です。フレーム 8 は、クライアントからの再送された接続要求です。フレーム9は再送された接続要求によってトリガされたTCP確認応答であり、フレーム10は別の再送された接続確認応答である。フレーム 11 は、クライアントからの別の接続要求ですが、新しい 2 番目の接続のためのものです。応答がなく、フレーム12は再送された接続要求を示していることに注意してください。フレーム 13 は接続確認応答を示していますが、これはまだ最初の接続に対するものです。フレーム14は、第2の接続要求の再送である。フレーム14は、第2の接続要求の別の再送である。フレーム15はクライアントからの新しい第3の接続要求を示しており、フレーム16および17は再送である。フレーム18は、第1の接続に対する接続確認応答の別の再送である。フレーム19はさらに別の接続要求で、フレーム20と21は再送であり、フレーム22は4番目の新しい接続要求です。最後に、フレーム23でSTCPは最初の接続要求をあきらめ、フレーム24で2番目の接続要求への接続確認応答とフレーム25での再送を伴うリセットを送信します。この時点でお分かりいただけたと思います。
STCPがタイムアウトするまでにかかった時間は、フレーム0からフレーム23までの合計106.9秒でした。クライアントはタイムアウト時にリセットを送信しませんが、2回目から3回目の接続要求が開始されるまでの時間(フレーム11からフレーム15まで)は29.152秒、3回目から4回目の接続要求が開始されるまでの時間(フレーム15からフレーム19まで)は25.8秒と、STCPよりもはるかに高速です。
これを防ぐためにはどうすればいいのでしょうか?
最良の解決策は、OpenVOS 17.1にアップグレードして、アプリケーションをPOSIXライブラリで再コンパイルすることです。これを行うことで、STCP はアプリケーションが accept を呼び出すのを待たずに直ちに接続確認応答を送信するので、問題が発生するのを防ぐことができます。ただし、アプリケーションの他の動作を変更する可能性がありますので、アプリケーションのテストは慎重に行う必要があります。アップグレードや再コンパイルが不可能な場合は、以下の方法があります。
- 接続確認応答をドロップしているステートフル・ネットワーク・デバイスをリセットで応答するように再構成します。STCPがリセットを受信すると、バックログ・キュー内の次の接続要求に移動します。その結果、ステートフルデバイスによってタイムアウトされた接続要求は、キューから速やかに排出されます。それ以上の接続確認は、クライアントによって処理され、クライアントはそれ自身のリセットを送信するか、それらを確認するかのいずれかになります。
- サーバのバックログキューが空になるまで、クライアントが接続要求を行うのを停止します。
- サーバーアプリケーションのリスニングソケットを閉じて、再度開きます。通常、アプリケーションはこれを行うように設計されていないため、サーバーアプリケーションを停止して再起動する必要があります。
- syn_rcvd_abort の値をクライアントのタイムアウト値よりも短い値に設定する。この値は analyze_system リクエストの set_stcp_param で変更されます。
analyze_system -request_line 'set_stcp_param syn_rcvd_abort 15' -quit OpenVOS Release 17.0.2au, analyze_system Release 17.0.2au 現在のプロセスは151、ptep 91530AC0、Noah_Davids.CACです。 TCP SYN_RCVDのタイムアウト(SYN_RCVD_ABORT)をOFFから15に変更する 用意ができました 11:07:44
上記の例では、タイムアウトは15秒に設定されています。有効な値は1から180の間で、0の値はデフォルト(約100秒)を使用することを意味します。
これにより、単一のクライアントがバックログキューに大量のデータを蓄積するのを防ぐことができます。値をどれくらい短くすべきかは、同時にサーバにアクセスしている多くのクライアントに依存します。このアプローチの問題点は、すべてのクライアントとすべてのサーバポートに影響を与えることです。さらに、低すぎる値を設定すると、タイマーが長ければ成功する可能性があるのに、高遅延リンクを経由する接続が失敗してしまうことがあります。最適な値を選択することは、科学よりも芸術です。