TCP队列满了导致web无法访问
TCP队列满了导致web无法访问
参考:性能分析之TCP全连接队列占满问题分析及优化过程(转载) - 寒冰宇若 - 博客园
介绍:
从图中明显可以看出建立 TCP 连接的时候,有两个队列:syns queue
(半连接队列)和accept queue
(全连接队列),分别在第一次握手和第三次握手。
半连接队列: 保存 SYN_RECV 状态的连接。
控制参数:
- 半连接队列的大小:min(backlog, 内核参数 net.core.somaxconn,内核参数tcp_max_syn_backlog).
- net.ipv4.tcp_max_syn_backlog:能接受 SYN 同步包的最大客户端数量,即半连接上限;
- tcp_syncookies:当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
accept队列-全连接队列:保存 ESTABLISHED 状态的连接。
控制参数:
- 全连接队列的大小:min(backlog, /proc/sys/net/core/somaxconn),意思是取backlog 与 somaxconn 两值的最小值,
net.core.somaxconn
定义了系统级别的全连接队列最大长度,而 backlog 只是应用层传入的参数,所以 backlog 值尽量小于net.core.somaxconn
; net.core.somaxconn
(内核态参数,系统中每一个端口最大的监听队列的长度);net.core.netdev_max_backlog
(每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目);- ServerSocket(int port, int backlog) 代码中的backlog参数;
- 文件句柄;
net.ipv4.tcp_abort_on_overflow
= 0,此值为 0 表示握手到第三步时全连接队列满时则扔掉 client 发过来的 ACK,此值为 1 则说明握手到第三步时全连接队列满时则返回 reset 给客户端。
解决:
TCP 连接队列的溢出数据统计情况,命令为:“netstat -s
”
1 | # 查看TCP半连接队列溢出: |
通过反复敲命令,可以看出这个 overflow 的值一直在增加,那么这个现象说明 server 的TCP 全连接队列的确是满了。这时候应该想到的是,全连接队列已经溢出了,下一步就应该看一下,全连接队列的占用情况,命令为:
参数说明:
- Recv-Q:全连接当前长度
- Send-Q:如果连接不是在建立状态,则是当前全连接最大队列长度
从上图第三列的 Send-Q
可以看出,5000 端口服务的全连接队列最大为 50,而 Recv-Q
为当前使用了多少。在压测过程中,查看指定端口的 TCP 全连接队列使用情况,如下:
1 | ss -lnt |grep 5000 |
上图可以看出,全连接队列几乎已经被占满,那么最终可以确定问题所在了。找到原因后,现在只要增大全连接队列的长度就可以了。
通过上面介绍的全连接队列中,我们知道全连接队列的大小为 backlog 和 somaxconn 的最小值,那么来看下 somaxconn 的取值。
1 | sysctl -a |grep net.core.somaxconn |
如果太少则增加就行:vim /etc/sysctl.conf
可以看出 somaxconn 的值是很大的,那就只有通知开发,增加应用代码中的 backlog 的值来加大全连接队列的长度。
扩展:
一、查看当前系统下所有连接状态的数
1 | netstat -n|awk '/^tcp/{++S[\$NF]}END{for (key in S) print key,S[key]}' |
二、看下我系统上默认的SYN队列大小
1 | [root@log]# cat /proc/sys/net/ipv4/tcp\_max\_syn\_backlog |
三、看下我系统上默认的TIME_WAIT队列大小
1 | cat /proc/sys/net/ipv4/tcp\_max\_tw\_buckets |
四、修改backlog参数
Kernel会为LISTEN状态的socket维护两个队列,一个是SYN RECEIVED状态,另一个是ESTABLISHED状态,而backlog就是这两个队列的大小之和。
当前Linux版本使用上面说法,有两个队列:具有由系统范围设置指定的大小的SYN队列 和 应用程序(也就是backlog参数)指定的accept队列。
五、查看系统默认数量:
1 | cat /proc/sys/net/core/netdev\_max\_backlog |
六、nginx 配置参数优化:
有代理就设置在代理上:没有代理就直接设置在web应用上(或者两个都设置)
1 | upstream js\_sdk { |
七、php优化:(-1 表示没有使用系统的 backlog )
vim /usr/local/php/etc/php-fpm.conf
listen.backlog = 2048 #每一个端口最大的监听队列的长度,需要配置nginx配置文件使用,如下(暂时只更改这里)
八、linux内核参进行优化:
vim /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096 #对于还未获得对方确认的连接请求,可保存在队列中的最大数目。如果服务器经常出现过载,可以尝试增加这个数字。
net.core.somaxconn = 4096 #定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数。backlog需要设置这个
使用命令使之生效:sysctl -p
转自:https://blog.csdn.net/u010917150/article/details/95621873