TIME_WAIT过多及解决
问题场景
大量高并发日志传输,短连接,每次在传输一定数量的日志后,开始出现以下错误
Failed to establish a new connection: [Errno 99] Cannot assign requested address
问题原因
通过下述命令可以查看当前端口占用及分类
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
TIME_WAIT 27352
SYN_SENT 4
ESTABLISHED 58
发现端口占用中处于TIME_WAIT状态的有多达20000+,基本占用了全部的端口,要详细了解端口状态,需要从TCP的状态转换说起。
其中TIME_WAIT状态的产生源自于TCP连接的结束,TCP要保证在所有可能的情况下使得所有的数据都能够正确被投递。当关闭一个 socket 连接时,主动关闭一端的 socket 将进入TIME_WAIT状态,而被动关闭一方则转入CLOSED状态。
当一个socket关闭的时候,是通过两端互发信息的四次握手过程完成的,当一端调用close()时,就说明本端没有数据再要发送了。这好似看来在握手完成以后,socket就都应该处于关闭CLOSED状态了。但这有两个问题:
1. 我们没有任何机制保证最后的一个ACK能够正常送达
2. 网络上仍然有可能有残余的数据包(wandering duplicates,或老的重复数据包),我们也必须能够正常处理。
正常的系统中,可分配的端口号是有限的,但是处于TIME_WAIT状态的连接,虽然已经要确认关闭了,但是仍然占住端口不撒手,一般需要2MSL的时间,现实时长大概在两分钟左右,所以在有限的端口使用完之后,新的请求没有可以安放的地方,便出现了上述错误。
解决方案
修改sysctl.conf
vim /etc/sysctl.conf # 文件中加入 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1
减少短时间内的请求数
这一条需要结合具体场景分析,像本例的场景,是一个短时间内高并发,短连接,每次传输的时间较短,所以可以考虑加大每次的请求的数据传输量,总量一定的情况下,请求数下来,端口使用也能得到一定程度的缓解。通过直接发送RTS来直接结束本次连接
这个方法暂时没实践,如果有时间,后期可能补上