Linux 带宽跑满但业务无异常的原因

5次阅读

top和htop看不到带宽占用进程,因其不统计网络I/O;真正瓶颈常在网络收发队列或内核协议,需用ss、iftop、tcpdump工具定位发包/收包进程及连接积问题。

Linux 带宽跑满但业务无异常的原因

为什么 tophtop 看不到带宽占用进程

因为 top 默认只显示 CPU 和内存使用率,不统计网络 I/O。即使网卡跑满,top 里所有进程的 %CPU 可能都低于 10%,业务响应也正常——这说明瓶颈不在 CPU 或磁盘,而在网络收发队列或内核协议处理能力上。

真正要查的是:谁在持续发包?谁在大量收包?有没有连接堆积?

  • ss -ti 查每个 TCP 连接的 retrans(重传)、qsize(发送队列长度)、rcv_space(接收窗口)
  • cat /proc/net/dev 确认是 rx 还是 tx 满载;若 rx 满但应用没读包,Recv-Q 会持续增长
  • iftop -P 能按端口实时看流量归属,但需 root 权限,且默认不解析进程名(加 -P 后仍可能显示 unknown,因部分流量走内核 bypass 路径如 XDP 或 AF_XDP)

netstat -s 里哪些字段暴露真实瓶颈

netstat -s 输出的是内核网络协议栈的统计,比进程级工具更接近真相。重点盯这几个字段:

  • TCP: packets receivedpackets to unknown port 差值大 → 大量 SYN 包打到未监听端口(如被扫描或配置错端口)
  • TCPSynRetrans 高 → 客户端反复重发 SYN,可能是防火墙丢包、SYN cookie 触发或后端服务未响应
  • tcpListenoverflows > 0 → net.core.somaxconn 不够,新连接被丢弃,但已有连接不受影响,所以业务“看似正常”
  • tcpBacklogDrop > 0 → accept 队列已满,新连接进不了用户态,但三次握手已完成,客户端以为连上了(造成假连接)

udp 流量满带宽却查不到对应进程

UDP 无连接、无状态,内核不会为每个包维护连接上下文,ss -ulsof -iUDP 只能列出“当前绑定端口”的进程,对发完就扔的 UDP 发送方(比如监控上报、日志采集、dns 查询)完全不可见。

这时候得从包层面切入:

  • tcpdump -i eth0 -c 1000 udp and port not 53 抓包,看源 IP/端口分布;如果大量来自同一本地端口,大概率是某个应用批量发 UDP
  • cat /proc/net/udp 查 UDP socket 绑定状态,注意 st 字段:07 表示 ESTABLISHED(仅对有连接语义的 UDP 封装有效),多数 UDP socket 是 01(RAW)
  • 检查 /etc/cron.d/ 或 systemd timer,有些日志轮转脚本会调用 logger 发 UDP 到 127.0.0.1:514,而 rsyslog 若未启用 $SystemMaxMessageSize 限制,可能被大日志撑爆带宽

业务无异常但 softirq 占用高

执行 top1 显示所有 CPU 核,再按 shift + H 切换线程视图,找 si(softirq)列持续 >80% 的核——这说明内核正在忙于处理网络中断和协议栈任务,但用户态进程还没被拖慢。

  • cat /proc/softirqsNET_RXNET_TX 计数是否远高于其他项(比如高出 10 倍)
  • 检查网卡是否启用了 RSS(Receive Side Scaling):若只有单核处理所有 RX 中断,NET_RX 会集中在某一个 CPU 上
  • 确认是否开了 irqbalance,并检查 ethtool -l eth0channel 数量是否匹配 CPU 核数;否则大量中断挤在 CPU0,softirq 成瓶颈,但业务进程调度不受直接影响

这种情况最易被忽略:带宽跑满不是因为业务逻辑在发数据,而是内核在替你“扛包”。一旦并发连接数再涨一点,或出现丢包重传,业务延迟就会突变。

text=ZqhQzanResources