解决Linux服务器大量TCP连接FIN_WAIT1的问题

Posted by

今天发现公司的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

😄,这里提供关于这个内核参数的函数地址,有兴趣的可以看看。不知道是不是torvalds老大,自己写的。

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.