TCP SOCKET中backlog参数的用途是什么?

本文深入探讨了PHP-FPM中backlog参数的作用与合理设置方法,分析了backlog大小对FPM处理能力和前端超时的影响,提供了计算backlog值的推荐公式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 简介

2013年12月14日发布的php5.5.6中,changelog中有一条变更这条改动是在10月28日改的,patch提交者认为,提高backlog数量,哪怕出现timeout之类的错误,也比因为backlog满了以后,悄悄的忽略tcp syn的请求要好。

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

backlog的定义是已连接但未进行accept处理的SOCKET队列大小,已是(并非syn的SOCKET队列)。如果这个队列满了,将会发送一个ECONNREFUSED错误信息给到客户端,即 linux 头文件 /usr/include/asm-generic/errno.h中定义的“Connection refused”,(如果协议不支持重传,该请求会被忽略

在linux 2.2以前,backlog大小包括了半连接状态和全连接状态两种队列大小。linux 2.2以后,分离为两个backlog来分别限制半连接SYN_RCVD状态的未完成连接队列大小跟全连接ESTABLISHED状态的已完成连接队列大小。互联网上常见的TCP SYN FLOOD恶意DOS攻击方式就是用/proc/sys/net/ipv4/tcp_max_syn_backlog来控制的

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

10306662-e35cd7598136bc74.png
image.png

如图,服务端收到客户端的syn请求后,将这个请求放入syns queue中,然后服务器端回复syn+ack给客户端,等收到客户端的ack后,将此连接放入accept queue。

系统默认参数

root@vmware-cnxct:/home/cfc4n# cat /proc/sys/net/core/somaxconn
128

fpm

root@vmware-cnxct:/home/cfc4n# ss -lt
State      Recv-Q Send-Q         Local Address:Port                    Peer Address:Port
LISTEN     0      128                        *:ssh                           *:*
LISTEN     0      128                 0.0.0.0:9000                           *:*
LISTEN     0      128                       *:http                           *:*
LISTEN     0      128                       :::ssh                           :::*
LISTEN     0      128                      :::http                           :::*

在FPM的配置中,listen.backlog值默认为511,而如上结果中看到的Send-Q却是128,可见确实是以/proc/sys/net/core/somaxconn跟listen参数的最小值作为backlog的值。

当backlog为某128时,accept queue队列塞满后,TCP建立的三次握手完成,连接进入ESTABLISHED状态,客户端(nginx)发送给PHP-FPM的数据,FPM处理不过来,没有调用accept将其从accept quque队列取出时,那么就没有ACK包返回给客户端nginx,nginx那边根据TCP 重传机制会再次发从尝试…报了“111: Connection refused”错。当SYNS QUEUE满了时,,不停重传SYN包。

对于已经调用accept函数,从accept queue取出,读取其数据的TCP连接,由于FPM本身处理较慢,以至于NGINX等待时间过久,直接终止了该fastcgi请求,返回“110: Connection timed out”。当FPM处理完成后,往FD里写数据时,发现前端的nginx已经断开连接了,就报了“Write broken pipe”。当ACCEPT QUEUE满了时,TCPDUMP的结果如下,不停重传PSH SCK包。

2.backlog大小设置为多少合适?

这跟FPM的处理能力有关,backlog太大了,导致FPM处理不过来,nginx那边等待超时,断开连接,报504 gateway timeout错。同时FPM处理完准备write 数据给nginx时,发现TCP连接断开了,报“Broken pipe”。backlog太小的话,NGINX之类client,根本进入不了FPM的accept queue,报“502 Bad Gateway”错。所以,这还得去根据FPM的QPS来决定backlog的大小。计算方式最好为QPS=backlog。对了这里的QPS是正常业务下的QPS,千万别用echo hello world这种结果的QPS去欺骗自己。当然,backlog的数值,如果指定在FPM中的话,记得把操作系统的net.core.somaxconn设置的起码比它大。另外,ubuntu server 1404上/proc/sys/net/core/somaxconn 跟/proc/sys/net/ipv4/tcp_max_syn_backlog 默认值都是128,这个问题,我为了抓数据,测了好几遍才发现。
对于测试时,TCP数据包已经drop掉的未进入syns queue,以及未进入accept queue的数据包,可以用netstat -s来查看

3.参考地址

http://www.cnxct.com/something-about-phpfpm-s-backlog/

<think>好的,我现在需要解释SO_BACKLOG参数是什么。首先,我得回忆一下之前用户的问题是关于Netty发送数据到物联网模块时遇到的问题,特别是连接断开后恢复的情况。用户现在想了解SO_BACKLOG的具体作用。 首先,我应该明确SO_BACKLOGTCP协议中的一个参数,和操作系统的网络栈有关。记得在Netty中配置ServerBootstrap的时候,会用到这个参数。可能需要解释它的作用,比如它控制的是连接请求队列的长度。 接下来,我需要分清楚半连接队列和全连接队列。半连接队列对应的是SYN队列,当客户端发送SYN但还没有完成三次握手时的状态;全连接队列则是已完成握手但尚未被应用接受的连接。SO_BACKLOG通常影响的是全连接队列的最大长度。 但不同操作系统可能有不同的实现方式,比如Linux中,SO_BACKLOG可能会影响SYN队列和已接受队列的长度,具体要看内核版本和参数设置。可能需要提到这一点,避免用户混淆。 然后需要说明在Netty中如何设置这个参数,比如使用.option(ChannelOption.SO_BACKLOG, 128)。这时候要提醒用户,这个值的设置需要根据实际负载和操作系统限制来调整,设置过小可能导致连接被拒绝,过大可能占用过多资源。 还需要举一个例子,比如当并发连接数突然增加时,如果队列已满,新的连接请求会被拒绝,导致客户端无法连接。这时候用户可能会看到连接超时或拒绝的错误。 另外,可能需要提到与操作系统限制的关系,比如Linux中的somaxconn参数,需要确保应用设置的SO_BACKLOG不超过操作系统的限制。可以通过sysctl命令查看和调整这些参数。 最后,结合用户之前的问题,当断开一个连接后恢复响应,可能是因为连接队列满,导致新的连接无法处理,断开一个后队列腾出空间,新的连接得以处理。因此合理设置SO_BACKLOG有助于避免这种情况。 需要确保用简洁明了的中文解释,避免技术术语过于晦涩,同时结构清晰,分点说明,帮助用户理解。同时提醒用户在实际应用中如何调整和监控这个参数,以及可能的注意事项。</think>**SO_BACKLOG参数**是TCP网络编程中的核心参数,它直接决定了服务端处理连接请求的缓冲能力。以下是深入解析: --- ### 一、本质作用 1. **队列管理机制** 当客户端发起TCP连接时,服务端内核会维护两个队列: - **半连接队列(SYN队列)** 存储收到SYN包但未完成三次握手的连接(`SYN_RECEIVED`状态)。 - **全连接队列(ACCEPT队列)** 存储已完成握手但未被应用层接受的连接(`ESTABLISHED`状态)。 **`SO_BACKLOG`** 参数主要控制**全连接队列的最大长度**。 2. **Netty中的体现** 在Netty服务端配置中设置: ```java ServerBootstrap b = new ServerBootstrap(); b.option(ChannelOption.SO_BACKLOG, 1024); // 关键配置点 ``` --- ### 二、工作流程(以Linux为例) 1. 客户端发送`SYN` → 服务端将连接放入**SYN队列** 2. 完成三次握手 → 连接迁移至**ACCEPT队列** 3. Netty的`bossGroup`线程调用`accept()` → 从ACCEPT队列取出连接 4. **队列溢出后果**: - **SYN队列满**:直接丢弃新SYN包(客户端重试) - **ACCEPT队列满**:忽略新完成的握手(客户端收不到响应) --- ### 三、配置注意事项 | 配置维度 | 说明 | |----------------|----------------------------------------------------------------------| | **操作系统层** | Linux通过`net.core.somaxconn`定义全局最大值(默认128) | | **应用层** | Netty中`SO_BACKLOG`值应 ≤ `somaxconn`(需`sysctl -w net.core.somaxconn=2048`调整) | | **经验值** | 高并发场景建议设置为`4096`,需配合压力测试验证 | --- ### 四、问题诊断方法 1. **监控队列状态** ```bash # Linux查看队列溢出情况 netstat -s | grep -E "SYNs|listen" ``` 输出示例: ``` 1890 times the listen queue of a socket overflowed 3290 SYNs to LISTEN sockets dropped ``` 2. **Netty日志增强** 启用DEBUG日志观察连接接受延迟: ```java ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ``` --- ### 五、典型问题案例 **现象**:服务端CPU利用率低但连接成功率骤降 **根因**:`SO_BACKLOG=512`,而实际每秒新连接达2000+,ACCEPT队列持续溢出 **解决方案**: - 调整`somaxconn=65535` - 设置`SO_BACKLOG=32768` - 扩容`bossGroup`线程数(需配合多端口监听) --- 通过合理配置`SO_BACKLOG`并结合操作系统参数优化,可显著提升服务端在高并发场景下的连接处理能力。建议在性能测试中通过逐步加压,找到业务场景下的最佳参数值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值