一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Linux TCP 协议栈内发送队列(Send-Q)溢出排查

时间:2026-07-13 08:38:01 编辑:袖梨 来源:一聚教程网

Linux TCP发送队列(Send-Q)溢出本质是套接字发送缓冲区满,导致send/write阻塞或返回EAGAIN;它属传输层缓冲问题,需从应用吞吐、对端接收能力及网络路径协同排查,区别于SYN/accept队列溢出。

Linux TCP 发送队列(Send-Q)溢出,本质是套接字的 发送缓冲区已满,导致内核无法继续缓存待发数据,应用调用 send()write() 可能阻塞或返回 EAGAIN/EWOULDBLOCK。它不同于半连接队列(SYN Queue)或全连接队列(Accept Queue)溢出,属于传输层缓冲行为,需从应用吞吐、对端接收能力和网络路径三方面定位。

确认 Send-Q 是否真实堆积

Send-Q 值在 ss -annetstat -an 输出中仅对 非 LISTEN 状态连接 有效,含义是“已发出但尚未被对端 ACK 确认的数据字节数”。持续高位(如 >100KB)且不回落,才提示潜在问题:

  • 运行 ss -tni 'sport == :80' | awk '$2 > 100000 {print $0}' 筛选 Send-Q 超 100KB 的 ESTABLISHED 连接
  • 对比同一连接的 rttrttvar:若 RTT 显著增大(如 >500ms)、RTT 方差飙升,说明对端接收慢或网络丢包,导致窗口停滞、重传堆积
  • 检查对端是否异常:如客户端崩溃、防火墙拦截 ACK、中间设备限速,都会造成发送端缓冲区持续积压

排查内核级 TCP 发送缓冲区丢包

Send-Q 溢出的最终表现是内核主动丢弃新数据包,指标为 tcpRcvQDrop(注意不是 packet receive errors):

  • 执行 grep Tcp /proc/net/snmp | awk '{print $19}' 获取 tcpRcvQDrop 计数;该值非零且持续增长,说明 socket 接收队列满导致丢包——但这反映的是本端接收队列满,间接影响对端 Send-Q;真正对应本端发送丢包的是 Tcp: InCwndFull(拥塞窗口满)或驱动层 drop,需结合 /proc/net/dev 中对应网卡的 drop 字段交叉验证
  • ss -i 显示某连接 cwnd 长期为 1 MSS 且 ssthresh 极低,大概率触发了拥塞控制降窗,发送速率被压制,缓冲区易堆积

检查应用层写入行为与 socket 配置

Send-Q 高往往源于应用未及时感知对端窗口关闭,或自身写入节奏失控:

  • 确认 socket 是否启用 TCP_NODELAY:若业务为小包高频交互(如 RPC),禁用 Nagle 算法可减少缓冲等待,避免小包攒批加重 Send-Q 压力
  • 检查应用是否忽略 send() 返回值:当返回值 < len 时,必须循环调用直到写完,否则残留数据滞留在内核缓冲区
  • 观察 SO_SNDBUF 设置:默认值通常 128KB~256KB,若业务需突发大块数据(如文件上传),可适当调大(setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val))),但需同步调整 net.ipv4.tcp_wmem

关联网络路径与对端状态

单看本机 Send-Q 无法闭环定位,必须协同分析链路两端:

  • tcptraceWireshark 抓包,重点观察:是否有大量重复 ACK(对端丢包)、窗口字段是否长期为 0(对端接收缓冲区满)、是否存在持续重传(超时未 ACK)
  • 检查对端主机:ss -tni 看其 Recv-Q 是否持续 >0,cat /proc/net/snmp | grep Tcp:tcpRcvQDrop 是否增长——若对端接收队列满,本端 Send-Q 必然堆积
  • 排查中间设备:运营商 QoS、云厂商安全组限速、硬件负载均衡器缓冲区设置,都可能导致 ACK 延迟或丢弃,诱发本端发送停滞

热门栏目