net.core.somaxconn过低导致accept队列溢出,表现为ss -lnt中Recv-Q长期非零或Connection refused;需设为65535并同步调整应用backlog参数。

.net.core.somaxconn 设置过低导致 accept 队列溢出
当 ss -lnt 显示 Recv-Q 长期非零,或应用日志频繁出现 Connection refused(尤其在突发流量下),大概率是 net.core.somaxconn 不足。该参数限制内核 listen socket 的全连接队列最大长度,不是应用层 backlog 参数能绕过的。
- 默认值通常为 128,远低于现代 Web 服务需求;建议设为 65535 或更高
- 需同时调整应用的
listen()第二个参数(如 Nginx 的listen ... backlog=65535),否则仍受其限制 - 修改后无需重启内核,但监听新端口的服务需重启才能生效(已有 listen socket 不会动态扩容)
- 验证方式:
sysctl net.core.somaxconn
和ss -lnt | grep :80
观察Recv-Q是否持续堆积
net.ipv4.tcp_tw_reuse 与 tcp_tw_recycle 的取舍
tcp_tw_reuse 在 TIME_WAIT 状态 socket 复用上安全有效;而 tcp_tw_recycle 已在 Linux 4.12+ 彻底移除,且在 NAT 环境下必然引发连接失败——它依赖时间戳单调递增,但多客户端共用公网 IP 时,内核无法区分不同设备的时间戳偏移。
- 只启用
net.ipv4.tcp_tw_reuse = 1,禁用tcp_tw_recycle(设为 0 或直接不配置) - 搭配
net.ipv4.tcp_fin_timeout = 30可进一步缩短 TIME_WAIT 持续时间(默认 60 秒) - 若仍有大量 TIME_WAIT,优先检查是否短连接滥用(如 HTTP 未复用连接),而非盲目调参
接收缓冲区自动调优失效的典型表现
当 net.ipv4.tcp_rmem 三元组中第二项(默认接收窗口)设得过大(如 4096 65536 16777216),反而可能让内核放弃自动缩放:因为最小值和最大值跨度过大,TCP 栈倾向于长期维持高缓冲,浪费内存且增加延迟。
- 推荐设置为
4096 131072 6291456(小、中、大三档合理拉开,但最大值不超 6MB) - 确认自动调优开启:
net.ipv4.tcp_window_scaling = 1(必须为 1) - 用
ss -i
查看单连接实际 rwnd 值,若长期卡在最小值,说明应用读取太慢或缓冲区被锁死 - 不要单独调大
rmem_max,它只影响setsockopt(SO_RCVBUF)上限,不改变 TCP 动态行为
net.core.netdev_max_backlog 过载引发丢包
该参数控制网卡中断后,软中断处理前,网络栈接收队列能暂存的数据包数量。当 ifconfig 或 /proc/net/dev 中 rx_dropped 持续增长,且无硬件错误,就是此队列溢出的明确信号。
- 默认值常为 1000,千兆以上网卡或高并发场景建议设为 5000–10000
- 需配合调大
net.core.dev_weight(默认 64),提升软中断一次处理的包数,避免 backlog 积压 - 注意:增大该值会增加内存占用(每个 sk_buff 约 2KB),不要无脑翻十倍
- 验证方法:
watch -n1 'cat /proc/net/snmp | grep -i "InErrs\|InNoRoutes"
,若InNoRoutes异常升高,也可能是 backlog 溢出后包被静默丢弃
ss -s、netstat -s、cat /proc/net/snmp 找出具体瓶颈类型,再针对性改参。内核网络栈各层耦合紧密,一个参数改错可能把问题转移到更难诊断的位置。











