日前内网的某个服务出现了总是返回失败的情况,输入 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
排查时发现该上机器上有大量的 TIME_WAIT 连接。并且服务日志中有 Too manay open files
的报错。
排查服务端程序问题
遇到这个问题时,首先想到的是程序本身是否有问题。服务端是用 golang 写的,,使用 net/http 包的 Client 时导致出现 TIME_WAIT 连接数过多主要有以下两种情况:
- 情形1:由于忘记读取响应的body导致创建大量处于TIME_WAIT状态的连接
- 情形2:连接的数量超过连接池的限制导致出现大量TIME_WAIT状态的连接
这种情况时由于持续超过连接池导致许多短链接被打开。
排查服务端程序后,未发现程序出现此类问题,因此从其他方向排查。
优化内核参数
执行 ulimit -a
查看文件描述符限制,发现 open files
一行的值为 1024。在当前的压力下,这个值显然过低了。
修改 /etc/security/limits.conf 来增大最大句柄数,1
* - nofile 65535
同时,为了让服务器能够快速回收和重用那些TIME_WAIT的资源,让每个TIME_WAIT早点过期。修改 /etc/sysctl.conf 增加以下内容:1
2
3
4net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
其中各参数含义如下
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时间
执行 sysctl –p
使内核参数生效
再用 netstat 查看,可以发现 TIME_WAIT 连接数快速下降,问题解决。
参考链接
使用golang的http.Client
容易出现TIME_WAIT上涨的几种情况和解决方案
web服务器下出现大量TIME_WAIT
linux服务器出现大量TIME_WAIT的解决方法