最近用http_load做压测,跑出来一大串“Cannot assign requested address ”的错误,查了一下,是TIME_WAIT过多导致的。因为短时间内有太多连接,所以占用了大量端口,同时关闭连接后又处于TIME_WAIT状态,端口不能复用,所以慢慢的无端口可用,所以就“Cannot assign requested address”了。
可以对内核参数进行优化:
sysctl -w net.ipv4.tcp_timestamps=1 开启对于TCP时间戳的支持,若该项设置为0,则下面一项设置不起作用
sysctl -w net.ipv4.tcp_tw_recycle=1 表示开启TCP连接中TIME-WAIT sockets的快速回收
echo 5000> /proc/sys/net/ipv4/tcp_max_tw_buckets
问题解决了,不过还是要来探讨一下,为什么会有TIME_WAIT,以及上面的修改是什么意思。
TIME_WAIT是TCP关闭连接中,主动关闭的一方,在接收到对方的FIN包,并给出ACK应答后,会进入的一个状态。下面的图来自《UNP》
为什么一定要有TIME_WAIT的状态?能否直接进入CLOSEED?不能,TCP是建立在不可靠网络上的可靠协议,主动方发送的ACK包可能延迟,从而触发被动方的FIN包重传,这一来一去,就是2MSL的时间。因此,必须要有这个状态,以保证TCP的可靠性。否则,如果当重传的FIN包到达后,可能导致两个问题:
1. 旧连接已经不在,只能返回RST包,被动关闭的一方无法关闭TCP连接
2. 新连接已经建立,FIN包可能对新连接有干扰。
所以,TIME_WAIT不能没有,但不能太多,该考虑限制它的数量。
tcp_tw_recycle:顾名思义就是回收TIME_WAIT连接,注意的是timestamp必须打开,网上有人说不用,其实是因为timestamp一般是默认打开的,这里有个陷阱,参考
http://www.pagefault.info/?p=416。
tcp_max_tw_buckets:很显然,用于控制TIME_WAIT数量的。
TCP/IP协议还有许多要了解的地方。