somaxconn 是什么
net.core.somaxconn 限制监听套接字上「已完成三次握手、等待应用 accept」的连接队列长度上限。应用调用 listen(backlog) 时申请的值会被内核截断为 min(应用 backlog, somaxconn),因此这个参数决定了全连接队列的物理天花板。旧内核默认 128,现代内核普遍是 4096。高并发短连接服务(Web 前端、API 网关、压测被打端)的偶发连接超时,往往就出在这里。
基本信息
| 参数 | net.core.somaxconn |
|---|---|
| 作用对象 | 全连接队列(已完成握手、待 accept) |
| 常见默认值 | 现代内核 4096,旧内核 128,以本机回读为准 |
| 实际生效值 | min(应用 listen backlog, somaxconn) |
| 关联参数 | net.ipv4.tcp_max_syn_backlog 管半连接队列 |
| 生效条件 | 修改后需监听进程重新 listen 才生效 |
典型使用场景
- Web 前端与 API 网关:瞬时并发建连高峰时队列被瞬间填满,客端表现为连接超时
- 被压测的服务端:压测机用大量短连接冲击时,先确认是全连接还是半连接队列溢出
- Java/Nginx 等应用调大 backlog 后仍无改善:内核上限没跟着放开,需要同步提 somaxconn
- 负载均衡后端的真实服务器:四层 LB 直连 RS,溢出会放大成首包超时
- 排查偶发丢包与重传:连接层症状容易和网络丢包混淆,用队列计数器区分
查看与修改
查看与修改
sysctl net.core.somaxconn # 读当前上限
sysctl -w net.core.somaxconn=8192 # 临时调大
# 持久化:/etc/sysctl.d/99-net-tuning.conf 写 net.core.somaxconn = 8192
# 应用侧还需把 backlog 提到同一量级,如 nginx: listen 80 backlog=8192;
# 或 server 段配置 backlog=8192(不同版本指令位置不同,以官方文档为准)
systemctl restart nginx # 监听进程必须重启才用上新上限验证队列与溢出
验证队列与溢出
ss -lnt | head # Listen 行的 Send-Q 即该监听套接字 backlog 上限
nstat -az TcpExtListenOverflows TcpExtListenDrops # 队列溢出与丢弃计数
nstat -az TcpExtListenOverflows | tail -1 # 隔一段时间再读一次,看计数是否在增长
netstat -s | grep -i -E 'listen|overflow' # 无 nstat 时的替代查法队列指标读法
| 指标 | 含义 | 异常信号 |
|---|---|---|
| ss 的 Send-Q | 监听套接字的 backlog 上限 | 远小于预期说明应用没接受新配置,或进程未重启 |
| ss 的 Recv-Q | 当前堆积的已完成连接数 | 持续贴近 Send-Q 说明 accept 速度跟不上 |
| ListenOverflows | 全连接队列满导致的丢弃次数 | 持续增长才是真溢出,偶发个位数可忽略 |
| ListenDrops | 各类监听丢包总计数 | 比 Overflows 大得多时同时看半连接与内存因素 |
改大 somaxconn 只是抬高上限,不改应用行为:listen backlog 仍取两者中的较小值。只改内核参数不调应用 backlog,通常是一条无效变更;反过来只调应用 backlog 而内核上限很小,也一样被截断。
队列溢出且应用 accept 不及时,症状是客户端偶发连接超时但服务端日志里看不到任何请求。排查顺序建议是:先看 nstat 的 ListenOverflows 是否增长,再用 ss -lnt 核对实际队列长度,最后才决定调参数还是优化应用的 accept 循环。
现代内核的 tcp_abort_on_overflow 决定溢出后的处理方式:默认丢弃握手让客户端重传(表现为延迟上升),置 1 则回 RST 让客户端立刻失败。生产上一般保持默认,把溢出计数作为容量告警而非靠 RST 暴露问题。
全连接队列与半连接队列是两套独立结构:前者由 somaxconn 与应用的 listen backlog 决定,后者由 tcp_max_syn_backlog 决定。客户端只发出 SYN、握手尚未完成时堆积在半连接队列,此时调 somaxconn 没有意义;握手已完成却没人 accept,才是全连接队列的问题。