事情本身不复杂,线索都在日志里。CentOS 7.9 上 nginx 前面没有负载均衡,压测到三千并发时有一小部分请求直接超时,nginx 日志里没有对应记录,netstat -s 的 listen overflows 每次压测都涨几百,somaxconn 已经调到 65535。

第一反应是「全连接队列受 somaxconn 和 listen backlog 双重限制,只改一个没用」,验证下来不成立。

原因不止一个,得分开看。nginx 自己 listen 的 backlog 没改,还是默认的 511,内核取两者中较小的。另一种情况是accept 跟不上,worker 被上游拖住,队列里的连接过期后被丢。

还有一种情况,SYN 队列溢出被当成全连接溢出,看错了计数器。

上来先确认到底是哪个计数器在涨

netstat -s | grep -iE 'listen|overflow|SYN'

再往下看 listen socket 当前的队列长度

ss -lnt | grep ':80'

接着确认配置里的 listen 有没有写 backlog

grep -rn 'listen 80' /etc/nginx/ && nginx -t

等前面都确认过,再核对内核侧的两个上限

sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog

恢复的判定其实很直接。同样的并发再压一轮,listen overflows 不再增长,ss 里 Send-Q 的峰值低于设定值,请求超时比例降到零。

backlog 只是缓冲,accept 慢的根因通常在 worker 数量和上游耗时;队列调得很大反而让超时表现得更隐蔽,客户端要等更久才失败。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189