今天发现公司的Swoole服务器,拥有大量的FIN_WAIT1的TCP连接。谷歌一番后,解决了这个问题。也学到很多知识,哈哈。
为什么会有FIN_WAIT1?
FIN_WAIT1是由于服务端主动关闭连接,服务器端发出请求后,等待客户端的响应。如果这时候连接已经断掉了,那么Linux内核会主动Retry再次多次发送主动关闭连接的请求。以Swoole来说,就是代码执行了Swoole的$serv->close($fd)方法。
这个请求的次数,Linux内核里默认是0。通过查看Linux的代码,会发现这个0并不是一次都不尝试的意思。而是,尝试次数为8。也就是说,服务端主动关闭连接如果客户端不响应,那么每个连接Linux都会默认尝试8次。对于维护大量连接的服务端来说,这就比较蛋疼了。要把这个值改小一点。
Swoole的心跳检测参数会导致FIN_WAIT1
用过swoole的人都知道,swoole有一个心跳检测的机制。可以设定几分钟检测一次死链接,然后把超时的连接全部踢掉。这些连接,会导致FIN_WAIT1的出现。
我们公司的Swoole服务器,维持了大量的这种FIN_WAIT1的连接。浪费了很多的CPU和内存,修改Linux内核参数降低了Retry的次数后,负载有明显的降低。
查询当前swoole服务器9501端口建立的连接数量
Linux命令:netstat -nat | grep -i “9501” | wc -l
查询Socket服务器里FIN_WAIT的连接的数量
netstat -nat | grep -i “FIN_WAIT” | wc -l
这个命令的结果同时包含FIN_WAIT1和FIN_WAIT2的连接,如果把FIN_WAIT改成FIN_WAIT1,查询结果就是FIN_WAIT1的数量。
修改FIN_WAIT连接的重试次数
vim /etc/sysctl.conf 打开内核配置文件。linux内核是不能直接修改的,把新的配置写入这个文件,会覆盖Linux内核的文件。
net.ipv4.tcp_orphan_retries = 1
把这行代码插入/etc/sysctl.conf 文件,就是把retry次数设为1。我个人是建议设置为2的,经过实测,设置为2,FIN_WAIT1的连接数量就从四位数降低到个位数了。
特别注意:这个地方不能设置为0。如果设置为0,代表重试8次。
最后使用sysctl -p 命令使配置生效。
内核源代码的地址
https://github.com/torvalds/linux/blob/master/net/ipv4/tcp_timer.c