Linux TCP发送队列(Send-Q)溢出本质是套接字发送缓冲区满,导致send/write阻塞或返回EAGAIN;它属传输层缓冲问题,需从应用吞吐、对端接收能力及网络路径协同排查,区别于SYN/accept队列溢出。
Linux TCP 发送队列(Send-Q)溢出,本质是套接字的 发送缓冲区已满,导致内核无法继续缓存待发数据,应用调用 send() 或 write() 可能阻塞或返回 EAGAIN/EWOULDBLOCK。它不同于半连接队列(SYN Queue)或全连接队列(Accept Queue)溢出,属于传输层缓冲行为,需从应用吞吐、对端接收能力和网络路径三方面定位。
Send-Q 值在 ss -an 或 netstat -an 输出中仅对 非 LISTEN 状态连接 有效,含义是“已发出但尚未被对端 ACK 确认的数据字节数”。持续高位(如 >100KB)且不回落,才提示潜在问题:
ss -tni 'sport == :80' | awk '$2 > 100000 {print $0}' 筛选 Send-Q 超 100KB 的 ESTABLISHED 连接rtt 和 rttvar:若 RTT 显著增大(如 >500ms)、RTT 方差飙升,说明对端接收慢或网络丢包,导致窗口停滞、重传堆积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 极低,大概率触发了拥塞控制降窗,发送速率被压制,缓冲区易堆积Send-Q 高往往源于应用未及时感知对端窗口关闭,或自身写入节奏失控:
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 无法闭环定位,必须协同分析链路两端:
tcptrace 或 Wireshark 抓包,重点观察:是否有大量重复 ACK(对端丢包)、窗口字段是否长期为 0(对端接收缓冲区满)、是否存在持续重传(超时未 ACK)ss -tni 看其 Recv-Q 是否持续 >0,cat /proc/net/snmp | grep Tcp: 查 tcpRcvQDrop 是否增长——若对端接收队列满,本端 Send-Q 必然堆积