いっぱい接続したいの
とあるホストに、TCP接続を張っては切るという処理をぐるんぐるん繰り返すベンチマーク的なプログラムを書いて動かしました。
最初のうちは期待した通りの動作をしてるんですが、途中から対向のホストにTCP接続できなくなってエラー出まくり。
$ netstat -tna | grep TIME_WAIT | wc -l 28230
これが原因ぽい。
KERNEL_SOURCE/Documentation/networking/ip-sysctl.txt によれば、
ip_local_port_range - 2 INTEGERS Defines the local port range that is used by TCP and UDP to choose the local port. The first number is the first, the second the last local port number. Default value depends on amount of memory available on the system: > 128Mb 32768-61000 < 128Mb 1024-4999 or even less. (snip)
ということで、計算してみると、
$ cat /proc/sys/net/ipv4/ip_local_port_range | awk '{print $2-$1}' 28232
さっき数えた TIME_WAIT の数とだいたい一致してる。
ここちょっとあやふやな記憶なんですが、コネクションテーブルの管理は、SIP:SPORT:DIP:DPORTをキーとしていたはず。で、今回のケースはSIP, DIP, DPORTが固定でSPORTだけが変化してって、28232個使い果たして一意性が保てなくなったんで、エラーになった、ってことだと思うす。実際、他のホストには接続張れましたし。
でで、
最初はTIME_WAITの滞留時間を短くすればいいのかなぁと思ったんすけど、TIME_WAITのコネクションを再利用するオプションがあったような記憶がうっすらあったので、さっきのip-sysctl.txtをgrepしたらお目当てのを発見。
tcp_tw_recycle - BOOLEAN Enable fast recycling TIME-WAIT sockets. Default value is 0. It should not be changed without advice/request of technical experts. tcp_tw_reuse - BOOLEAN Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. Default value is 0. It should not be changed without advice/request of technical experts.
おお。この2つの値を変えて、件のベンチマーク的なプログラムを実行した結果は以下の通り。
recycle | reuse | netstat -tna | wc -l |
---|---|---|
0 | 0 | →たくさん。繋げなくなりエラーになる。 |
0 | 1 | →たくさん。エラーにはならない。 |
1 | 0 | →最大で3000個ぐらいまで増えるけどすぐに減る。 |
1 | 1 | →最大で3000個ぐらいまで増えるけどすぐに減る。 |
最初のエラーになるケースを除いては、秒あたりの接続数はどれも同じぐらい。
挙動だけ見るとrecycle,reuseが1,0の場合と1,1の場合のは同じぽいんですが、recycleだけを1にするべきなのか、両方1にするべきかはわからず…
↓の参考文書にも書いてますが、この設定はWebサーバなんかでも有効なんじゃないかと思います。特に、keepaliveをOffにしている場合とか。
以下、参考。
- http://www.linux.or.jp/JM/html/LDP_man-pages/man7/tcp.7.html
- IBM Redbooks | Tuning Red Hat Enterprise Linux on IBM eServer xSeries ServersにあるPDFの「3.14.8 Advanced networking options」(65,66ページ)にtcp_tw_reuseとtcp_tw_recycleについての言及あり。有効/無効を比較したグラフもあり。ここ以外にもこの文書はチューニングの参考になりそう。
追記 2020-11-16
- net.ipv4.tcp_tw_recycle は廃止されました ― その危険性を理解する
- tcp_tw_recycle は kernel 4.12 で廃止