当前位置:首页 > 运维 > 正文内容

高并发场景下backlog详解

phpmianshi5年前 (2016-04-04)运维534

本文详解高并发场景下backlog的配置和作用


环境介绍: PHP 7.3.5 +nginx/1.16.0 +Linux VM_0_15_centos 3.10.0-514.26.2.el7.x86_64


backlog定义:


已连接但未进行accept处理的SOCKET队列大小,并非syn的SOCKET队列。如果这个队列满了,将会发送一个ECONNREFUSED错误信息给到客户端,即 linux 头文件 /usr/include/asm-generic/errno.h中定义的“Connection refused”


在linux 2.2以前:

在底层维护一个由backlog指定大小的队列。服务端收到SYN后,返回一个SYN/ACK,并把连接放入队列中,此时这个连接的状态是SYN_RECEIVED。当客户端返回ACK后,此连接的状态变为ESTABLISHED。队列中只有ESTABLISHED状态的连接能够交由应用处理。第一种实现方式可以简单概括为:一个队列,两种状态。


linux 2.2以后:

在底层维护一个SYN_RECEIVED队列和一个ESTABLISHED队列,当SYN_RECEIVED队列中的连接返回ACK后,将被移动到ESTABLISHED队列中。backlog指的是ESTABLISHED队列的大小。SYN_RECEIVED队列的大小由/proc/sys/net/ipv4/tcp_max_syn_backlog系统参数指定,ESTABLISHED队列由backlog和/proc/sys/net/core/somaxconn中较小的指定。


当前最流行的DoS(拒绝服务)与DDos(分布式拒绝服务)的方式之一,这是一种利用TCP协议缺陷,导致服务器保持大量的SYN_RECV状态的“半链接”,并且会重试默认的5次回应第二个握手包,塞满TCP等待连接队列,耗尽资源(CPU满负载或内存不足),让正常的业务请求连接不进来。


TCP 3次握手

可分为4步

1 客户端发起connect(),发送SYN j
2 服务器从半链接队列(syn queue)中建立条目,响应SYN k, ACK J+1
3 客户端connect()成功返回,响应ACK K+1,服务器将socket从半链接队列(syn queue)移入全连接队列(accept queue),accept()成功返回

如何观察socket overflow 和 socket droped。

如果应用处理全连接队列(accept queue)过慢则会导致socket overflow

影响半连接队列(syn queue)溢出而导致socket dropped

[root@VM_0_15_centos ~]# netstat -s | grep -i listen    
62678 times the listen queue of a socket overflowed
65640 SYNs to LISTEN sockets dropped

如果SYN socket overflow和socket droped急剧增加的话则说明,TCP的三次握手是存在很大的问题的。

验证
  1. 查看全连接队列(accept queue)溢出之后,OS处理设置:

    • 0:表示如果三次握手第三步的时候全连接队列满了那么server扔掉client发过来的ack(在server端则会认为连接没有建立起来),server过一段时间再次发送syn+ack给client(也就是重新走握手的第二步),如果client超时等待比较短,client就很容易异常了。

    • 1:表示如果三次握手第三步的时候全连接队列满了,server端就会发送一个reset包给client端,表示废弃这个握手过程和这个链接。(在server端也会认为连接没有建立起来)

    • cat /proc/sys/net/ipv4/tcp_abort_on_overflow

  2. 设置tcp_abort_on_overflow为1

    • echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow

    • 查看server端的web服务是否存在许多的connection reset peer错误。



在使用listen函数时,内核会根据传入参数的backlog跟系统配置参数/proc/sys/net/core/somaxconn中,二者取最小值,作为“ESTABLISHED状态之后,完成TCP连接,等待服务程序ACCEPT”的队列大小。在kernel 2.4.25之前,是写死在代码常量SOMAXCONN,默认值是128。在kernel 2.4.25之后,在配置文件/proc/sys/net/core/somaxconn (即 /etc/sysctl.conf 之类 )中可以修改。

[root@VM_0_15_centos ~]# cat /proc/sys/net/core/somaxconn
32768
[root@VM_0_15_centos ~]# cat /usr/local/php/etc/php-fpm.conf |grep backlog
listen.backlog = 1024
[root@VM_0_15_centos ~]# ss -ln |grep -E 'php|Netid'
Netid  State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
u_str  LISTEN     0      1024   /dev/shm/php-cgi.sock 79785144              * 0


可见: 内核会根据传入参数的backlog跟系统配置参数/proc/sys/net/core/somaxconn中,二者取最小值

我这里php-fpm 配置的 listen = /dev/shm/php-cgi.sock ,如果你配置的 tcp监听9000,应该用如下命令验证

[root@VM_0_15_centos ~]# ss -lt
State      Recv-Q Send-Q Local Address:Port             Peer Address:Port                
LISTEN     0      1024   0.0.0.0:9000               *:*


backlog大小设置为多少合适?


1、backlog太大了,导致php-fpm处理不过来,nginx那边等待超时,断开连接,报504 gateway timeout错。同时php-fpm处理完准备write 数据给nginx时,发现TCP连接断开了,报“Broken pipe”。

2、php-fpm的backlog太小的话,nginx之类的client请求,根本进入不了php-fpm的accept queue,报“502 Bad Gateway”错。所以,这还得去根据php-fpm的QPS来决定backlog的大小。计算方式最好为QPS=backlog。建议设置在1024以上,最好是2的幂值(因为内核会调整成2的n次幂)


SYN queue长度由tcp_max_syn_backlog指定,accept queue则由net.core.somaxconn决定,listen(fd, backlog)的backlog上限由somaxconn决定.



php-fpm下backlog配置

php-fpm.conf进行配置

listen.backlog = 1024  默认值是 511 ,是在2014年7月22日修改的, Set FPM_BACKLOG_DEFAULT to 511


其中理由是“backlog值为65535太大了。会导致前面的nginx(或者其他客户端)超时”,假设FPM的QPS为5000,那么65535个请求全部处理完需要13s的样子。但nginx(或其他客户端)已经等待超时,关闭了这个连接。当FPM处理完之后,再往这个SOCKET ID 写数据时,却发现连接已关闭,得到的是“error: Broken Pipe”,在nginx、redis、apache里,默认的backlog值都是511。故这里也建议改为511。



nginx下backlog配置

/etc/nginx/nginx.conf进行配置

listen       80 backlog=8192; # 默认为511


linux下backlog配置


/etc/sysctl.conf 进行配置

net.core.somaxconn = 1048576 # 默认为128
net.core.netdev_max_backlog = 1048576 # 默认为1000
net.ipv4.tcp_max_syn_backlog = 1048576 # 默认为1024


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

SonarQube的安装、配置与使用

SonarQube的安装、配置与使用

sonarqube 是一个代码质量管理平台,可通过安装不同的插件集成测试工具、代码质量分析工具、持续集成等多种功能。sonarqube 目前最新版为 8.0,最新稳定版本为 7.9,由于性能原因,so...

记一次laravel项目因opcache导致的include过慢问题

问题表现 php-fpm-slow.log 大量如下日志:script_filename = /data/nginx/webroot/app-20200611-160330-feb...

jmeter压测实战

jmeter压测实战

下载安装下载JDK  : https://download.oracle.com/otn-pub/java/jdk/15.0.2+7/0d1cfde4252546c6931946de8db4...

linux中配置sudo赋予普通用户对某些命令的执行权限

背景有时我们需要给普通用户,某个命令的执行权限,但是又不想让这个普通用户能执行更多的其他命令,这时候我们可以配置sudo,设置只能执行某几个命令即可配置vim /etc/sudoers #...

快速删除复制代码中的行号

有时我们copy的代码中前面有行号,一个一个删除太麻烦可以用下面三种方式删除行号:1.awk操作 awk '{for(i=2;i<=NF;i++)printf(&qu...

sentry磁盘占用过大如何清理历史数据

1、SENTRY数据软清理 (清理完不会释放磁盘,如果很长时间没有运行,清理时间会很长)#登录worker容器 docker exec -it sentry_onpre...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。