最近使用C++开发libcurl库访问OpenSearch程序,出现”Cannot assign requested address”错误,大量请求错误。Google后问题集中在linux下的TIME_WAIT上。
出现TIME_WAIT的原因是短连接耗尽了系统的socket端口号,新的连接分配不到端口号,所以才产生的上述错误。
短链接耗尽端口号的原因得从TCP/IP的底层说起。
TCP/IP关闭链接时会使用我们通常所属的4次握手协议,这是就出现了服务端确认关闭链接后客户端发送确认后还需要等待一段时间,这段时间客户端会把链接置为TIME_WAIT状态,通常TIME_WAIT时间为2个msl,大概为60s左右,根据服务器设置而不同。
出现TIME_WAIT后会导致网络访问缓慢,请求失败等一系列的问题。为了解决这个问题就需要设置TIME_WAIT的时间。在网上搜了一大圈,方法都几种在修改内核参数,修改的方式如下(实验以后是没有生效,解决不了问题,贴出来供大家参考):
使用命令:vi /etc/sysctl.conf
编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后执行/sbin/sysctl -p让参数生效。
net.ipv4.tcp_syncookies = 1表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout修改系統默认的TIMEOUT时间
最后问了小康,最终搞定了,实在感谢小康。其实修改关键的内核参数是下面的:
net.ipv4.tcp_tw_timeout = 3
修改这个参数以后让链接关闭以后处在TIME_WAIT 3s的时间。这个再看网络链接,数量已经大大降低,从原先耗尽的端口,现在高并发访问最多占用4000个端口。
分析一下第一种修改的timeout参数,从参数名称上就可以看出来,其实是FIN_WAIT的时间,并不是TIME_WAIT的时间。只是协议里边第一次等待的时间。为什么修改的net.ipv4.tcp_tw_recycle = 1这个参数不起作用现在也还没有搞清楚。