必须同步调整内核参数net.core.somaxconn与net.ipv4.tcp_max_syn_backlog、应用层listen()的backlog值,并启用tcp_syncookies=1,否则单改任一参数均无法解决连接队列溢出问题。

直接调高 net.core.somaxconn 是最必要一步,但只改它几乎一定失效——因为半连接队列、应用层 listen() 的 backlog 参数、甚至 tcp_syncookies 状态都会卡住实际效果。
怎么确认真有队列溢出而不是误判
别一上来就改内核参数。先看证据:
- 运行
ss -lnt | grep :端口,重点看Recv-Q(当前已建立但未被accept()取走的连接数)是否长期 ≥Send-Q(该端口全连接队列上限)。接近或等于就是积压信号 - 查丢包统计:
awk '/^TcpExt/ {print $1,$2}' /proc/net/snmp | grep SynsToListenDrops。这个值持续上涨,说明半连接队列满,SYN 包被内核静默丢弃 - 搜日志:
dmesg | grep -i "possible SYN flooding"。出现这条,基本等于tcp_syncookies=0且半连接队列已爆
为什么必须同步改 net.ipv4.tcp_max_syn_backlog
Linux 2.2+ 内核里,net.core.somaxconn 不再管半连接队列,而是由 net.ipv4.tcp_max_syn_backlog 控制。但两者存在隐式取小逻辑:
- 半连接队列实际大小 =
min(net.core.somaxconn, net.ipv4.tcp_max_syn_backlog) - 全连接队列实际大小 =
min(listen() 的 backlog 参数, net.core.somaxconn) - 所以如果只把
net.core.somaxconn改成 65535,但net.ipv4.tcp_max_syn_backlog还是默认 128,那半连接队列还是卡在 128
建议统一设为相同值,例如:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
echo "net.core.somaxconn = 4096" >> /etc/sysctl.conf echo "net.ipv4.tcp_max_syn_backlog = 4096" >> /etc/sysctl.conf sysctl -p
应用层 listen() 的 backlog 参数常被忽略
内核参数调再高,应用自己调用 listen(fd, backlog) 时传个 128,最终全连接队列上限还是 128:
- Nginx:需在
listen 80 backlog=4096;中显式声明,不能依赖默认 - uWSGI:默认
--listen=100,得改成--listen=4096 - Spring Boot:对应
server.tomcat.accept-count,必须和net.core.somaxconn对齐 - Go/Python 启动 HTTP server 时,若支持
max_connections或backlog选项,也得同步设
注意:修改后监听该端口的服务进程要重启,已有 listen() socket 不会动态扩容。
tcp_syncookies 不是可选项,是兜底必需项
哪怕你把两个队列都设到 65535,在突发流量或扫描攻击下仍可能瞬间打满。此时 tcp_syncookies=1 能让内核跳过队列、用加密 Cookie 机制临时承载三次握手,避免丢包:
- 临时启用:
echo 1 > /proc/sys/net/ipv4/tcp_syncookies - 永久生效:加一行
net.ipv4.tcp_syncookies = 1到/etc/sysctl.conf并sysctl -p - 注意:它不能替代合理调参,只是防止“雪崩式丢包”的最后一道防线
真正容易被忽略的是:这三个层级(内核半/全队列 + 应用 backlog + syncookies)必须同时检查、同步对齐。少一个,调参就白做。










