调高 net.core.somaxconn 必须同步调整 net.ipv4.tcp_max_syn_backlog 并匹配应用层 listen() 的 backlog 值,否则仍会因隐性限制导致队列溢出;还需启用 tcp_syncookies 作为兜底防护。

直接调高 net.core.somaxconn 是解决监听队列溢出最基础也最关键的一步,但它不是孤立生效的——它会同时约束全连接队列(accept queue)上限,并隐式截断半连接队列(SYN queue)的实际大小。只改这一个参数,常会发现“改了没用”或“还是丢 SYN”。下面说清楚怎么调、为什么这么调、以及容易踩的坑。
确认当前队列是否真的溢出
别急着改参数,先看证据:
- 执行
ss -lnt | grep :端口,关注 Recv-Q(当前全连接队列中已建立但未被 accept 的连接数)和 Send-Q(该端口全连接队列上限)。如果 Recv-Q 长期接近甚至等于 Send-Q,说明全连接队列在积压 - 查内核统计:
awk '/^TcpExt/ {print $1,$2}' /proc/net/snmp | grep SynsToListenDrops。这个值持续增长,代表 SYN 包被直接丢弃,是半连接队列溢出的明确信号 - 看日志:
dmesg | grep -i "possible SYN flooding",出现该提示往往意味着半连接队列满且tcp_syncookies=0
同步调整两个核心参数
net.core.somaxconn 和 net.ipv4.tcp_max_syn_backlog 必须一起调,否则单改一个会被另一个“卡脖子”:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 内核实际采用的半连接队列上限 =
min(net.core.somaxconn, net.ipv4.tcp_max_syn_backlog) - 全连接队列上限 =
min(listen() 的 backlog 参数, net.core.somaxconn) - 所以建议把两者设为相同值,例如都设为
65535或保守些的4096,避免隐性限制 - 写入配置:
echo "net.core.somaxconn = 4096" >> /etc/sysctl.conf,同样追加net.ipv4.tcp_max_syn_backlog = 4096 - 立即生效:
sysctl -p
检查并匹配应用层 listen() 的 backlog
即使内核参数调高了,如果应用自己调用 listen(fd, backlog) 时传的值太小,最终队列仍会被这个值卡住:
- 比如 uWSGI 默认
--listen值是 100,哪怕somaxconn=4096,实际全连接队列上限仍是 100 - Nginx 默认不显式设 listen backlog,会走系统默认值(常为 128),需在
listen 80 backlog=4096;中显式声明 - Spring Boot 内置 Tomcat 对应的是
server.tomcat.accept-count,需设为与somaxconn一致 - Go/Python 等语言启动服务时,若支持设置
backlog或max_connections,也要同步对齐
启用 SYN Cookie 作为兜底防护
在突发流量或攻击场景下,队列再大也可能瞬间打满。开启 tcp_syncookies 可临时绕过队列限制,避免丢包:
- 执行
sysctl -w net.ipv4.tcp_syncookies=1,或写入/etc/sysctl.conf - 注意:启用后
SynsToListenDrops计数可能不再增长,但代价是无法使用 SACK、时间戳等高级 TCP 特性,且 CPU 开销略增 - 它不是替代调参的方案,而是最后一道防线,建议长期开启

















