队列溢出是怎么发生的
TCP 握手过程中连接在内核里排队等待应用 accept,队列分两段:SYN 队列(半连接,收到 SYN 尚未完成握手)与 accept 队列(已完成握手等待应用取走)。两段各有上限,超限时内核按策略丢弃:SYN 队列满可启用 SYN cookies 兜底;accept 队列满时默认丢弃最终 ACK,客户端表现为连接超时并重试。诊断第一步就是分清是哪一段在溢出。
基本信息
| SYN 队列上限 | net.ipv4.tcp_max_syn_backlog |
|---|---|
| accept 队列上限 | 应用 listen 的 backlog 与 net.core.somaxconn 取较小值 |
| 溢出计数 | netstat -s 的 listen queue of a socket overflowed、SYN cookies sent |
| 队列直读 | ss -lnt 的 Recv-Q(已握手待 accept)与 Send-Q(当前上限) |
| 溢出行为 | net.ipv4.tcp_abort_on_overflow=0 丢 ACK 让对端重试,为 1 则直接 RST |
典型使用场景
- 客户端间歇性连接超时、重试后又成功,疑似队列溢出
- 发布或秒杀瞬间连接大量涌入,短时排队超过上限
- 应用 accept 或首包处理偏慢,瓶颈在应用侧而非网络侧
- 调参前后验证:改完 backlog 与 somaxconn 看溢出计数是否还在增长
- 容量评估:区分应用处理能力不足还是排队容量不足
看计数与队列
看计数与队列
netstat -s | grep -iE 'overflow|listen|syn cookie' # 累计溢出与 SYN cookies 计数
ss -lnt # Recv-Q 逼近 Send-Q 即 accept 跟不上
ss -s # 全局连接状态汇总
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog net.ipv4.tcp_abort_on_overflow
sysctl -w net.core.somaxconn=4096 # 抬高 accept 队列硬上限
netstat -s | grep -c 'listen queue' # 采样两次做差值才有意义字段逐列读法
| 字段 | 含义 | 异常表现 |
|---|---|---|
| Recv-Q(LISTEN) | 已完成握手、等待 accept 的连接数 | 持续贴近 Send-Q 说明应用取连接太慢 |
| Send-Q(LISTEN) | 该监听套接字当前的 accept 队列上限 | 等于 backlog 与 somaxconn 的较小值 |
| listen queue overflowed | accept 队列满导致丢弃的累计次数 | 持续增长即为真实溢出 |
| SYN cookies sent | 半连接队列满时用 cookies 兜底应答的次数 | 大量增长说明 SYN 队列被打满,疑似泛洪 |
| tcp_abort_on_overflow | 0 丢 ACK 让客户端重试,1 立即回 RST | 为 1 时客户端报连接被重置 |
这些都是累计计数,必须比较两次采样的差值;单次读数无法判断溢出是否仍在发生。
accept 队列的真实上限取应用 listen(backlog) 与 somaxconn 的较小值,只调 sysctl 不改应用参数等于没调。
溢出多半是应用 accept 慢或处理慢的结果而非根因;调大队列只是争取缓冲,积压点会从内核队列转移到应用内部。