ListenOverflows计数持续上涨即确认全连接队列溢出,需执行awk '/^TcpExt/ {for(i=1;i

怎么确认 ListenOverflows 计数在涨
内核不会写日志告诉你“全连接队列满了”,它只默默把已完成三次握手的连接丢掉,并累加 ListenOverflows 计数。这是最直接的证据。
执行这条命令查看当前值:
awk '/^TcpExt/ {for(i=1;i<p>如果这个数字在业务高峰期持续上升,基本可以锁定是全连接队列溢出。注意:该计数只增不减,重启网络服务或系统才会清零。</p>
-
netstat -s | grep -i "listen overflows"也能看到,但老版本netstat(如 net-tools 1.60)可能漏掉该字段,优先读/proc/net/snmp - 该值和
SynDrop完全无关——后者是 SYN 队列满,前者才是 accept 队列满 - 若值为 0 但仍有连接失败,可能是应用层
accept()调用阻塞、线程卡死,或被信号中断未重试
ss -lnt 的 Recv-Q 和 Send-Q 怎么看
ss -lnt 输出中,LISTEN 状态行的 Recv-Q 表示当前已三次握手完成、等待被 accept() 取走的连接数;Send-Q 是该监听 socket 全连接队列的**实际容量上限**。
运行:
ss -lnt | grep ':80'
观察类似这样的输出:
LISTEN 0 128 *:80 *:*
其中 0 是当前 Recv-Q,128 是 Send-Q(即队列上限)。关键判断逻辑是:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 若
Recv-Q长期 ≥Send-Q(比如稳定在 128/128),说明队列已满,新完成握手的连接会被内核丢弃 -
Send-Q实际生效值 = min(应用调用listen(sockfd, backlog)传入的值,net.core.somaxconn内核参数),二者需同步调大 - 即使
Recv-Q显示为 0,也不能排除溢出——因为溢出是瞬时事件,而ss是快照,需配合ListenOverflows增长趋势交叉验证
为什么调大 somaxconn 还是溢出
常见误区是只改 net.core.somaxconn,却忽略应用层 listen() 调用传入的 backlog 参数。内核取两者最小值作为最终队列长度。
例如:
- 系统设置
sysctl net.core.somaxconn=4096 - 但 Nginx 默认
listen 80 backlog=511,Go 的net.Listen("tcp", ":80")默认传 128 - 最终队列上限仍是 128 或 511,不是 4096
解决办法:
- 对 Nginx,在
listen指令后显式加backlog=4096 - 对自研服务,确保
listen(sockfd, 4096)中第二个参数足够大 - 检查是否启用了
SO_REUSEPORT:多个进程监听同一端口时,每个进程都有独立队列,总容量是 N × 单队列上限,但单个进程仍可能单独溢出
应用层没及时 accept 的典型表现
全连接队列溢出,本质是应用消费能力跟不上连接建立速度。最典型的线索是:
- CPU 使用率不高,但
ListenOverflows持续上涨 -
ss -i查看 ESTABLISHED 连接时,大量连接的timer字段显示keepalive或on,但没有新连接进入 - 应用日志里出现
accept: Resource temporarily unavailable(对应EAGAIN),说明accept()非阻塞模式下队列为空,但更危险的是阻塞模式下线程卡在accept()调用上(比如被信号中断未重试、或锁竞争导致线程无法调度) - 用
strace -p $PID -e trace=accept,accept4观察应用是否真正在调用accept(),调用频率是否匹配连接到达速率
真正难排查的不是参数调小,而是应用逻辑本身没做连接消费——比如用单线程 accept 后扔进慢速队列,或 accept 后未立即读取,导致后续 accept 被阻塞。










