Nginx高并发调优中常被忽略的参数
在nginx或php-fpm优化的时候,经常会碰到一个参数:backlog
backlog是什么?
在nginx官方文档中定义如下:
在php-fpm中解释如下:
从上面的解释来看,就是定义了一个队列,并设置了队列长度,那么这个队列是做什么的,接着往下看
不管是nginx还是php-fpm中backlog配置的地方都是在listen指令的位置,为什么是在listen指令的位置配置,通过一张图来看下
我们知道,listen是用来创建一个监听,打开一个端口、文件描述符,用于等待客户端请求,上面这张图是TCP内核的请求过程
client发送SYN到server,将状态修改为SYN_SEND,如果server收到请求,则将状态修改为SYN_RCVD,并把该请求放到syns queue队列中
server回复SYN+ACK给client,如果client收到请求,则将状态修改为ESTABLISHED,并发送ACK给server
server收到ACK,将状态修改为ESTABLISHED,并把该请求从syns queue中放到accept queue
上面过程中的状态看着是不是很熟悉,我们通常在服务器上通过ss或netstat查看端口状态的时候,其实就是TCP连接状态
而syns queue和accept queue是由操作系统内核维护的两个队列
在操作系统中这两个队列分别由两个内核参数定义
就是上图中的net.core.somaxconn和net.ipv4.tcp_max_syn_backlog
这两个参数也是通常你看到的优化nginx文章中推荐要设置的两个参数,如上图,net.ipv4.tcp_max_syn_backlog参数决定了SYN_RECV状态队列也就是syns queue队列的长度,一般默认值为512或1024,根据服务器内存,可以通过/proc/sys/net/ipv4/tcp_max_syn_backlog查看,超过这个数量,系统将不再接受新的TCP连接请求,这里说明下,不再接受新的请求,但是不会发送reset等,而是对SYN包不再响应SYN/ACK包,通常只是丢弃SYN包,这种设计方法就比较优雅,不返回RST,客户端可以进行重试,在内核中同样也有参数配置,通过net.ipv4.tcp_syn_retries参数可以配置SYN重试次数,这样在队列腾出空闲位置时,客户端可以重新建立连接,而不是直接被reset
但是这个参数的生效和tcp_syncookies又有一定的联系,在linux的系统调用的man文档中
在syncookies启用的情况下,逻辑上没有最大值限制,这个设置被忽略,syncookies通常被开启,用于防止SYN Flood攻击
简单说一下syncookies,syncookies设计就是用来防止SYN Flood攻击的,它的原理是,在TCP服务器接收到TCP SYN包并返回TCP SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值,这个cookie作为将要返回的SYN ACK包的初始序列号,当客户端返回一个ACK包时,根据包头信息计算cookie,与返回的确认序列号(初始序列号+1)进行对比,如果相同,则时一个正常连接,然后分配资源,建立连接
扯远了,接着说另外一个参数net.core.somaxconn,该参数决定了listen监听队列的大小,也就是accept queue队列的大小。在使用listen函数时,内核会根据传入的backlog参数与系统内参参数somaxcoon,取其中最小值作为backlog的值,这也就是上面为上面backlog参数配置在listen指令的位置了
这个参数在内核中通常默认128,可以通过 /proc/sys/net/core/somaxconn查看,接着通过简单测试测试backlog值的选择
首先是初始配置,内核是默认128,nginx默认511(这个在源码中可以查看),然后通过ss查看
下图是nginx源码中对backlog的定义
接着修改内核参数somaxconn为1024,再通过ss查看
查看nginx对应的Send-Q
从上面的结果来看确实是根据最小值来决定backlog的,所以你之前配置的内核参数,对于nginx来说,默认情况下,不管你设置多大,这个队列都是511,并没有达到优化的效果
那么对于nginx,对于php-fpm,backlog应该设置多大,是越大越好吗?下篇文章通过压测来看下backlog怎么设置合适
上面关于内核参数的更多内容可以通过linux内核官方手册查找https://www.kernel.org/doc/man-pages/
推荐阅读更多精彩内容请扫描下方二维码关注公众号