tcp_max_syn_backlog 调大后 backlog full 的 listen backlog 同步调整

6次阅读

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

tcp_max_syn_backlog 调大后 backlog full 的 listen backlog 同步调整

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(常见于 nginxredis、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.somaxconntcp_max_syn_backlog(后者影响半连接队列,和这里无关)。

最容易被忽略的是:改完 net.core.somaxconn 后没重启服务进程——很多服务只在启动时读一次该值,运行中修改内核参数对已启动进程无效。

text=ZqhQzanResources