TCP/IP で TIME_WAIT が残る時間を短くする
SERVER
TIME_WAIT 状態の TCP コネクションが多数残る
netstat コマンドで TCP コネクションの状態を確認していると、"TIME_WAIT" という状態のコネクションがたくさん確認される場合があります。
"TIME_WAIT" 状態というのは TCP コネクションにおいて、こちら側から通信をした場合に "FIN_WAIT_1" (FIN ACK 受信) から、"FIN_WAIT_2" (ACK 受信) または "CLOSING" (FIN 受信, ACK 送信)を経て、コネクションを閉じられる状態となったことを示すもののようです。
そしてこの "TIME_WAIT" から、実際にそのコネクションが閉じられて "CLOSED" となるまでの間に待ち時間があり、これによって、短時間に通信が集中すると、その分だけ通信終了間際の "TIME_WAIT" 状態のコネクションが多数、netstat により検出されるという状態が起こります。
この "TIME_WAIT" から "CLOSED" までの待ち時間の意味なのですが、調べてみるとどうやらこれは、通信が終了した後にも何らかの理由でネットワーク上をさまよっていた遅延パケットが到着して、その時に同じポート番号で新たに通信を開始した別のプログラムと衝突しないようにするための時間的余裕を持たせるもののようでした。
この "TIME_WAIT" が残っているとその資源を再び利用するこどができませんが、ネットワーク資源は有限なため、これが多数残っていると新しい接続が行えなくなる可能性も出てくることと思います。
遅延パケットとの兼ね合いで取られている猶予時間ですから、これを短くするともしかして通信エラーにつながる可能性もあるのかもしれないですが、アクセス数が非常に多いサーバーなどではこの待ち時間を短くすると、TCP コネクションの許容数を実質的に引き上げられるかもしれません。
Linux で TIME_WAIT の猶予時間を変更する
CentOS 5.4 の場合、"/proc/sys/net/ipv4/tcp_tw_recycle" を 1 に設定したうえで、"/proc/sys/net/ipv4/tcp_fin_timeout" に TIME_WAIT の残る時間を秒単位で設定することで、TIME_WAIT の猶予時間を変更することができるようでした。
変更の際には上記のファイルに直接値を書き込む方法もありますが、CentOS 5.4 の場合は次の行を "/etc/sysctl.conf" ファイルに追記することで調整できるようでした。
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 50
このように編集することで、規定値の 60 秒から 50 秒に値を変更することが可能です。
他にも "net.ipv4.tcp_tw_reuse" という設定項目もあり、これを 1 にすることで、システムの判断で "TIME_WAIT" 状態のコネクションを再利用するように設定することもできるような感じですけど、CentOS 5.4 では既定で無効になっていることや、これを有効にしたことでどのような影響が出る可能性があるのかを判断できなかったため、今回はこれは 0 のままにしておきました。
上記のように "/etc/sysctl.conf" を編集したら、あとは次のコマンドを実行することで、設定内容がシステムに反映されます。
sysctl -p
なお、一時的に設定したい場合には、"sysctl" コマンドを利用して、次のように設定を行うことも可能です。
sysctl -w net.ipv4.tcp_fin_timeout=50
このようにすれば、"/etc/sysctl.conf" の値を変えないまま、実際の設定値のみを変更することが可能です。
注意点としては、このときキーと値とを隔てる = の前後には空白を入れてはいけないような感じです。空白文字を入れてしまうと 'error: "net.ipv4.tcp_fin_timeout" must be of the form name=value' というようなエラーメッセージが表示されてしまいます。
また、単に設定値を確認したい場合には、次のようにすることでも可能です。
sysctl -n net.ipv4.tcp_fin_timeout
このコマンドを打つのが簡単なのか、それとも "/proc/sys/net/ipv4/tcp_fin_timeout" ファイルの値を参照するのが簡単なのか、どちらが良いかはわからないですけど、とりあえずこういった方法で値を確認する方法もあったので、備忘録として記しておくことにします。
Windows で TIME_WAIT の猶予時間を変更する
Windows で TIME_WAIT 状態のコネクションの待ち時間を設定するにはレジストリーの値を調整する必要があるようです。
HKEY_LOCAL_MACHINE -> SYSTEM -> CurrentControlSet -> Services -> Tcpip -> Parameters ->
上記のようにキーを辿って、その中に "DWORD" 型で "TcpTimedWaitDelay" という値を用意したら、その値として TIME_WAIT の猶予時間を秒単位で設定します。ちなみに Windows の場合、規定値は 240 に設定されているらしいです。
この値を調整したら Windows を再起動することで、設定値がシステムに反映されます。
余談になりますが、Windows では上記のレジストリーキーの中で "DWORD" 型の "MaxUserPort" として数値を設定することで、一時的な TCP/IP コネクションで使用されるポートの数を調整することができるようになっているようです。
厳密には、"MaxUserPort" で設定できるのは、ポート番号指定なしでコネクションの利用を要求したアプリケーションに対して割り当てられるポート番号の上限値を設定するもので、下限は 1025 と定められているようです。そのため、例えば規定値の 5000 を設定した場合、1025 から 5000 までの 3976 個が利用可能なポートの数となる感じです。
これは Web サーバーのような、1 つのポートで相手からの要求を処理する場合にはあまり関係ないかもしれないですけど、Web サーバーが内部でデータベースサーバーと接続するために TCP コネクションを開始するような場合には、このポート数が不足したがためにデータベースとの新規接続が行えないような場面では、コネクションの許容量アップに効果があるものと思われます。