两级队列与溢出行为
服务端每处理一个 SYN,内核就把连接放进两个队列:握手未完成的半连接队列,以及已完成握手、等待应用 accept 的全连接队列。应用在 listen 时给的 backlog 只是请求值,全连接队列上限取 min(backlog, net.core.somaxconn),半连接队列由 tcp_max_syn_backlog 约束。溢出时默认丢弃 ACK,客户端会先经历延迟再重传,表现为高峰期偶发连接超时。
基本信息
| 适用平台 | Linux(其他系统的参数名与行为不同) |
|---|---|
| 全连接队列 | ss -lnt 的 Recv-Q 为当前排队数,Send-Q 为实际队列上限 |
| 溢出信号 | netstat -s 中 listen queue of a socket overflowed 计数持续增长 |
| 溢出策略 | tcp_abort_on_overflow 为 0 时丢弃 ACK 让客户端重传,为 1 时直接回 RST |
| 半连接队列 | 受 tcp_max_syn_backlog 与 tcp_synack_retries 影响 |
关键参数读法
| 参数 | 作用 | 调整建议 |
|---|---|---|
| net.core.somaxconn | 全连接队列的系统上限 | 高并发服务调到 32768 到 65535 |
| tcp_max_syn_backlog | 半连接队列上限 | 配合 somaxconn 同步调大 |
| tcp_abort_on_overflow | 溢出时是否回 RST | 保持 0,避免业务侧看到连接被重置 |
| tcp_synack_retries | SYN-ACK 重传次数 | 过大延长半连接占用,过小易误判 |
| 应用 backlog | listen 的请求值 | 按并发连接数设置,不能小于业务峰值 |
生产常用配置
生产常用配置
# /etc/sysctl.d/99-tcp-queue.conf
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_abort_on_overflow = 0 # 0=丢 ACK 让客户端重传(客户端感知为延迟)
net.ipv4.tcp_synack_retries = 3
# 生效后核对:ss -lnt 的 Send-Q 应等于应用 backlog 与 somaxconn 的较小值典型使用场景
- 高峰期偶发连接超时,怀疑 accept 速度跟不上时排查队列溢出
- 压测前统一定调 somaxconn 与应用 backlog,避免队列成为瓶颈
- 排查 SYN 洪水:观察半连接队列与 syncookies 是否启用
- 容器环境下确认 netns 内的参数是否需要单独设置
队列溢出的典型表现是客户端偶发连接超时,且只在高峰期出现:因为此时应用忙着处理已有连接,accept 循环跟不上,队列被填满后新连接被丢弃。
调大队列只是买时间:真正的解法是提升 accept 与业务处理速度(多进程、多线程或异步模型),否则队列越大,故障时的雪崩越晚发生但更猛烈。