listen backlog 仍满是因为其实际长度取应用传入值与 net.core.somaxconn 的较小者,与 tcp_max_syn_backlog 无关;需同步调大 somaxconn 并重启服务生效。

tcp_max_syn_backlog 调大后 listen backlog 为什么还是满?
因为 tcp_max_syn_backlog 和应用层 listen() 的 backlog 参数是两套独立机制,内核不会自动同步。调大前者,不等于 accept 队列(即 listen backlog)变长——后者由你调用 listen(sockfd, backlog) 时传入的值决定,且受内核参数 net.core.somaxconn 限制。
listen() 的 backlog 实际生效值怎么算?
Linux 内核会取你传给 listen() 的值和 net.core.somaxconn 的较小者。即使你传 1024,若 net.core.somaxconn = 128,实际队列长度就是 128。
- 检查当前值:
sysctl net.core.somaxconn - 临时调大:
sysctl -w net.core.somaxconn=4096 - 永久生效:写入
/etc/sysctl.conf并执行sysctl -p - 服务端代码中,
listen(sockfd, 4096)的 4096 必须 ≤net.core.somaxconn,否则被截断
accept 队列满(backlog full)的典型现象
不是连接失败,而是连接建立后卡在 SYN_RECV 或 ESTABLISHED 状态迟迟不被 accept() 拿走,表现为:
- 客户端看到连接成功但请求超时
-
ss -lnt显示 Recv-Q 持续非 0(如 128),说明 accept 队列已满 - dmesg 里出现
possible SYN flooding on port XXX. Sending cookies.(这是触发 syncookies 的提示,不一定真被攻击) - 日志中反复出现
backlog full(常见于 Nginx、Redis、Node.js 等日志)
Go / Python / Node.js 中如何正确设置 listen backlog?
多数高级语言封装了 listen(),但默认值往往偏小,且不随系统参数自动更新。
- Go:
net.Listen("tcp", ":8080")底层用的是SOMAXCONN值,但 Go 1.19+ 已默认用net.core.somaxconn;旧版本需确认 runtime 源码或手动调大系统值 - Python:
socket.listen(1024)中的 1024 会被内核 clamp,仍受限于net.core.somaxconn - Node.js:
server.listen(port)默认用系统SOMAXCONN,但某些版本(如 v16 之前)硬编码为 511,需升级或改用server.listen({ port, backlog: 4096 })
真正起作用的永远是:应用传入值 ≤ net.core.somaxconn ≤ tcp_max_syn_backlog(后者影响半连接队列,和这里无关)。
最容易被忽略的是:改完 net.core.somaxconn 后没重启服务进程——很多服务只在启动时读一次该值,运行中修改内核参数对已启动进程无效。










