必须同步调大net.ipv4.tcp_max_syn_backlog和net.core.somaxconn至相同值(如65535),因内核取二者最小值作为半连接队列实际上限;还需匹配应用层listen()的backlog参数,否则仍被截断。

net.ipv4.tcp_max_syn_backlog 和 net.core.somaxconn 必须一起调
只改 net.ipv4.tcp_max_syn_backlog 几乎一定无效。内核实际取 min(net.ipv4.tcp_max_syn_backlog, net.core.somaxconn) 作为半连接队列上限,所以两个值必须同步设为相同目标值(比如 65535),否则生效的仍是较小的那个。
临时生效命令是:
sysctl -w net.ipv4.tcp_max_syn_backlog=65535 sysctl -w net.core.somaxconn=65535
永久生效需在 /etc/sysctl.conf 中添加两行:
net.ipv4.tcp_max_syn_backlog = 65535 net.core.somaxconn = 65535
然后运行 sysctl -p 加载。
应用层 listen() 的 backlog 参数会再次截断
即使内核参数已调高,如果应用程序调用 listen(fd, backlog) 时传入的 backlog 值更小,最终队列仍以该值为准——这是用户空间对内核队列的“再限制”。
- Nginx 默认用
511,需显式写listen 80 backlog=65535; - Redis 默认也是
511,配置项是tcp-backlog 65535 - 自研服务若用
socket()+listen(),必须把第二个参数设为期望值;若用 Netty,需设置ChannelOption.SO_BACKLOG
验证方式:ss -lnt | grep :端口,看 Send-Q 是否达到你设的目标值。
别忽略 tcp_syncookies 开关和超时控制
当半连接队列真的被填满时,net.ipv4.tcp_syncookies = 1 是兜底手段:它让内核跳过队列存储,用加密 Cookie 响应 SYN,避免直接丢包。但这是权衡方案——Cookie 计算开销略高,且不支持部分 TCP 扩展选项(如 timestamps)。
同时,缩短半连接存活时间也能缓解压力:
-
net.ipv4.tcp_synack_retries = 1(默认是5,总超时约 3 分钟) - 配合
net.ipv4.tcp_syn_retries = 3可进一步压缩重传窗口
这些参数不扩容队列,但能加快条目释放,提升单位时间吞吐能力。
怎么确认半连接队列真在溢出
别只盯着 ListenOverflows(那是全连接队列溢出),要看半连接专属指标:
执行:awk '/^TcpExt/ {print $1,$2}' /proc/net/snmp | grep SynsToListen,输出类似 SynsToListenDrops 127 表示已被丢弃的 SYN 数量。这个数字持续上涨,说明队列确实不够用。
另一个交叉验证方式:netstat -s | egrep "SYNs to LISTEN",关注 “ignored” 后面的计数。
真正容易被忽略的是:即使所有参数都调高了,如果应用没重启、或 systemd 服务没 reload,旧进程仍跑在旧 backlog 下——改完内核参数和配置后,务必重启对应服务进程。


















