サーバーへの頻繁なTCP(HTTP)接続を行う単一のクライアントアプリケーションがあります。接続は1つの要求の間続き、サーバーは接続を閉じるため、サーバーのソケットはTIME_WAIT状態になります。クライアントアプリケーションが繰り返し要求を行うと、サーバー上のTIME_WAIT接続の数が増え、TIME_WAITに常に存在する最大150個のソケットに落ち着きます。
時折、クライアントからの新しい接続が、サーバー上でTIME_WAIT状態にある最近使用された一時的な送信元ポートを選択し、接続が失敗することがあります。 TIME_WAITに32kのエフェメラルポート範囲と150のソケットがある場合、これが発生する可能性は10%を超えます。正確なシナリオは RFC6056セクション2. でも説明されています
サーバーを制御できないため、TIME_WAITの遅延を減らしたり、動作を変更したりすることはできません。また、サードパーティのライブラリを使用してHTTPリクエストを作成しているため、ソースポートを手動で選択するためにクライアントアプリを変更することも困難です。
エフェメラルポートの範囲を拡大しても、衝突の可能性はわずかに減少します。このような衝突を回避するために、クライアント(Linux)のエフェメラルポート選択戦略を変更する方法はありますか?
TIME-WAIT
のソケットは、同じ5タプル(プロトコル、送信元IP、送信元ポート、宛先IP、宛先ポート)を使用するデバイスからの新しい接続を喜んで受け入れます。ただし、新しい接続の初期シーケンス番号(ISN)が提供されます。前の接続で見られた最後のシーケンス番号よりも高いです。 RFC 1122 によると:
接続がアクティブに閉じられると、2xMSL(最大セグメントライフタイム)の間、TIME-WAIT状態のままである必要があります。ただし、次の場合は、リモートTCPから新しいSYNを受け入れて、TIME-WAIT状態から直接接続を再開することができます。
(1)新しい接続の初期シーケンス番号を、前の接続インカネーションで使用した最大シーケンス番号よりも大きくするように割り当てます。
(2)SYNが古い重複であることが判明した場合、TIME-WAIT状態に戻ります。
Linuxマシンでこれをテストするには、エフェメラルポート範囲を単一のポートecho 32769 32769 > /proc/sys/net/ipv4/ip_local_port_range
に設定してから、Connection: Close
HTTPヘッダーセットwget --no-http-keep-alive www.example.com
を使用してWebサイトに複数の連続した要求を行います。すべての接続の5タプルが同じであっても、新しい接続ごとのISNはソケットで最後に表示されたシーケンス番号よりも大きい必要があるため、サーバーはTIME-WAIT中に新しい接続を受け入れます。 Linuxでは、新しい接続のISNは常に増加しているはずです。これは、システムクロックにある程度関係しています。
TIME-WAITが常にサーバー側で終了し、エフェメラルポートが再利用されたときに接続できないと確信している場合は、クライアントが使用するISNが新しい接続ごとに増加してはなりません(おそらく選択されています)。ランダムにまたは常に同じ値を使用しますか?)。クライアントからの新しい接続ごとに、前回よりも高いISN値を使用することができる場合は、問題なく接続できるはずです。