backlog 与两个队列
应用调用 listen(fd, backlog) 时,内核为监听 socket 维护半连接队列(收到 SYN、握手未完成)与接受队列(握手完成、等应用接受)。backlog 是应用给出的长度上限,内核会按 net.core.somaxconn 截断,最终生效值取两者较小者;半连接队列还受 net.ipv4.tcp_max_syn_backlog 与同步 cookie 机制影响。队列溢出时新连接会被丢弃或降级处理,客户端看到的是超时或重试。
基本信息
| 适用平台 | Linux(BSD 系参数语义相近,上限取值不同) |
|---|---|
| 相关参数 | net.core.somaxconn、net.ipv4.tcp_max_syn_backlog、net.ipv4.tcp_abort_on_overflow |
| 生效规则 | 监听队列上限取应用 backlog 与 somaxconn 的较小值 |
| 查看方式 | 监听行的发送队列列为上限,接收队列列为已建连未接受数 |
典型使用场景
- 高并发短连接服务在突发流量下出现连接超时或拒绝,需要确认是队列容量不足还是应用消费太慢。
- 内核溢出计数持续增长,需要区分是接受队列溢出还是半连接队列溢出。
- 调整 nginx 的 backlog、Node 的 listen 第二参数、Tomcat 的 acceptCount 后,核对最终生效值。
- 压测复现「已建连但应用报错」,判断瓶颈在握手阶段还是在应用接受环节。
- 新服务上线的首包延迟跳变排查,确认队列长度与连接建立速率是否匹配。
读取生效值
读取生效值
ss -lnt | head -5 # 监听行:发送队列列即 backlog 上限,接收队列列为已建连未接受数
ss -lnt 'sport = :8080' # 只看某个端口,避免被其它监听行干扰
ss -lntp | grep nginx # 结合进程名确认是哪个服务在监听
sysctl net.core.somaxconn # 内核允许的最大值,应用值再大也会被它截断
nstat -az TcpExtListenOverflows TcpExtListenDrops # 观察两类溢出计数是否在增长两类队列的区分
| 队列 | 堆积特征 | 对应计数 |
|---|---|---|
| 半连接队列 | 握手未完成的条目堆积 | 同步 cookie 发送数与队列溢出计数 |
| 接受队列 | 已建连但应用未接受,接收队列列上升 | 接受队列溢出计数 |
| 应用侧 | 接受后处理阻塞,连接在工作线程排队 | 只看队列看不出,需要应用内埋点 |
backlog 只是上限,不解决消费速度:应用接受慢或处理阻塞时,队列再大也只是把溢出时间往后推,容量与消费能力要一起看。
只把内核上限调大而应用仍用默认 backlog(或反之)不会有任何效果——内核取的是两者较小值,两侧都要改,改完用监听行的队列列复核。