2009年11月10日火曜日

TIME_WAIT にやられた

WAN で連帯するシステムで、動的IPって何だよ!の続きです。
 まぁ、最初の話では、当然固定IPで、サーバOSを入れるに決まってんだろーという話をしていたんです。それが、どこをどう転がれば、動的IPとWinXPにDBサーバとGISのサーバをぶっこんで、そのマシンでクライアント・アプリも動かして、IISが稼働してSoapのISAPIからGISサーバやDBサーバに更新かけて、ペンティアム4のシングル・コア、メモリ2Gで動いてます…って話になるんだよ!という構成のシステムがあってですね。
 負荷をかけると、途中で外部センターからのデータ送信が失敗するという現象が起こる…ってんで、現調してました。どうも、そのマシン内でのTCP接続が途中で失敗しているのが原因みたいでした。ISAPI の DLL から、TCP接続をかけていて、TCPのクライアント側からちゃんと切断しているけども、netstat -a で見ると TIME_WAIT の嵐!
 センターから IIS への Soap 通信は、HTTP/1.1 の接続で、Keep-Alive が効いているので、一度に大量の更新をかけても基本的に接続数が増えない。しかし、Soap の1リクエスト毎に TCP 接続しているので、こちらの後処理がうまく行っていなければ問題である。IIS への Soap 通信も細切れになる可能性は十分にある。自前で書いてる部分は、TIME_WAIT でも SO_REUSEADDR オプションを指定して回避は可能であるけども、IIS 等はアウト・オブ・アンダーコントロールである。TIME_WAIT に絡む設定を調べていくうちに、WinXP では、ポートの最大接続数は 5000で、切断までの最大待ち時間は 120 秒で、サーバ用途では少なくとも、5000, 60秒という設定になるらしい事が判明した。負荷も考えると短時間に大量に接続と切断が繰り返されるのであれば、20000, 30秒ぐらいでも良いと思う。
 参考1参考2
 ちなみに、boost::asio で、コントロールしようと思うと、こんな感じになるのでしょうか…。

 納得が行かないのは、自前で書いたTCPの切断…。CLOSE_WAIT や TIME_WAIT とかが気持ち悪いので、クライアントから切断するようにしたのに、ゴミが残る???見ると、ウィルス・チェッカーがパケットをスニッフしていて同じように TIME_WAIT をしてる…。うーん…クライアントから切断時に FIN が飛んでないのか?ウィルス・チェッカーが行儀悪いのか?何か別の原因か?

 とりあえず、ISAPI.DLL からは、どうせ同一マシン内の接続しか無いようなので、スピード・アップと TIME_WAIT 対策も兼ねて UDP で接続する事にし、レジストリのパラメータを

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort = 20000
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay = 30

という風にする事で回避する事にした。

2009/11/11 追記: TIME_WAIT は迷子になったパケットが到着するための受け口として存在するようです。よって、正規の動作と考えて良いみたいです。ちなみに非同期IOでコントロールしていれば、迷子もクソも無さそうに思えます。

0 件のコメント: