recv-q和send-q在ss命令中并非缓冲区容量,而是未被应用读取或未被确认的数据字节数;listen状态下分别表示待accept连接数和全连接队列上限,established状态下则反映接收/发送缓冲区积压量,持续非零是拥塞或应用瓶颈的早期信号。

Recv-Q 和 Send-Q 不是“当前缓存大小”,而是“未被应用读取/未被内核发送”的字节数;它们持续非零,才是拥塞的早期信号。
ss -i 输出里 Recv-Q/Send-Q 到底代表什么
很多人误以为这两个值是 TCP 接收/发送缓冲区总容量,其实不是:Recv-Q 是已收到、但应用还没调用 recv() 或 read() 读走的数据字节数;Send-Q 是应用已写入 socket、但内核尚未真正发出(或已发但未被 ACK)的数据字节数。
关键点:
- 正常交互中,这两个值应频繁归零或仅短暂非零(比如几 KB)
- 若某连接
Recv-Q长期 > 100KB,大概率是应用读太慢(阻塞、卡死、逻辑缺陷) - 若
Send-Q长期 > 64KB 且retrans字段也在涨,说明对端接收窗口(rwnd)持续为 0 或极小,链路已被压垮 -
ss -i必须加-i才显示retrans、rwnd、rtt等关键字段,否则无法判断是否真拥塞
用 ss -tan 和 ss -ti 区分“连接堆积”和“真实拥塞”
ss -tan 只看状态分布,适合发现异常连接数(如大量 TIME-WAIT);但判断拥塞必须进一层,用 ss -ti 查具体连接指标。
实操建议:
- 先快速筛查高 Send-Q 连接:
ss -ti | awk '$2 > 100000 {print $0}'(筛选 Send-Q > 100KB 的连接) - 再查对应连接的重传与窗口:
ss -ti dst 192.168.1.100:8080(替换为目标 IP:port) - 重点盯三个字段:
retrans(> 0 就危险)、rwnd(接近 0 表示接收方失能)、bytes_acked与bytes_received差值过大说明 ACK 延迟严重 - 避免只看
ESTABLISHED数量——它可能全是空闲长连接,Recv-Q/Send-Q才反映真实压力
Recv-Q 持续不为 0 的常见原因和验证方式
Recv-Q 居高不下,90% 不是网络问题,而是应用层没及时消费数据。但必须排除其他干扰项才能下结论。
排查路径:
- 确认进程是否存活且未挂起:
ps -p $(ss -tup | grep :8080 | awk '{print $7}' | cut -d',' -f2 | cut -d'=' -f2) -o pid,comm,state - 检查该进程的 fd 缓冲区使用:
cat /proc/<pid>/fdinfo/<fd></fd></pid>(从ss -tup获取 fd 编号)中的st_size字段,若远大于 Recv-Q,说明数据卡在 socket 层之下(如 TLS 解密未完成) - 用
strace -p <pid> -e trace=recv,read</pid>观察是否真有系统调用阻塞或返回 0(对端关闭) - 注意:某些框架(如 Node.js 的
http.Server)默认启用 Nagle,小包会攒批,导致 Recv-Q 短暂升高,属正常行为
Send-Q 卡住时,别急着调 sysctl
Send-Q 高 + 重传上升,第一反应不该是改 tcp_retries2,而要确认是不是路径上某环节彻底堵死。
更有效的动作顺序:
- 立刻运行
tc -s qdisc show dev eth0,看backlog是否持续增长且drops在跳——这是内核出口队列已满的铁证 - 用
iftop -P tcp看哪个目标 IP 占用出口带宽最多,再结合nethogs定位到进程 - 检查是否启用了
netem类规则:tc qdisc show dev eth0 | grep netem,这类人为丢包规则会直接让 Send-Q 堆积 - 确认网卡 offload 是否干扰统计:
ethtool -k eth0 | grep tx,若tx offload启用,tc统计可能不准,临时关掉再测:ethtool -K eth0 tx off
真正容易被忽略的是:Recv-Q/Send-Q 异常往往不是孤立现象,它和 qdisc backlog、/proc/net/snmp 中的 TcpRetransSegs 增速必须交叉验证——单看一个指标,90% 会误判。











