排查丢包时,先盯住/proc/net/dev里的Rx-DRP和Rx-OVR,通常就能把问题快速分层定位清楚:如果Rx-OVR>0,基本可以判断是Ring Buffer溢出,也就是硬件级丢包;如果Rx-DRP>0且Rx-OVR==0,那问题多半出在内核协议栈这一层。再往下,就配合ethtool -S去看rx_over_errors、rx_fifo_errors、rx_missed_errors、rx_dropped这些指标,同时用tc -s qdisc核实是否存在人为限流。

直接看 /proc/net/dev 里的 Rx-DRP 和 Rx-OVR 两列,就能快速锁定丢包发生在哪一层:前者是内核协议栈丢的,后者是网卡硬件就扔了——90% 的真实丢包问题靠它俩就能初步分清。
先盯死 /proc/net/dev 的 Rx-DRP 和 Rx-OVR
这是最轻量、最稳定的第一入口,不用装工具、不依赖驱动版本:
Rx-OVR > 0:Ring Buffer 溢出,包根本没进内存,tcpdump -i eth0抓不到这些包。立刻执行ethtool -g eth0查当前 rx 值,若为 256 或 512,高吞吐下极易溢出,可试ethtool -G eth0 rx 4096Rx-DRP > 0且Rx-OVR == 0:包已进 Ring Buffer,但在内核处理阶段被丢。下一步该查netstat -s | grep "packet receive errors"或cat /proc/net/softnet_stat第二列(dropped)是否同步上涨- 虚拟网卡(如
virtio_net)可能不暴露Rx-OVR,此时若Rx-DRP上涨 +dmesg | grep -i "missed"出现提示,基本锁定 vCPU 调度不及时
用 ethtool -S 看驱动级真实丢包字段
/proc/net/dev 是通用统计,而 ethtool -S 输出的是驱动原生计数器,字段更准、分层更细。别用 grep -i drop——它会漏掉关键指标,也会把重传、过滤等伪丢包当真问题:
rx_over_errors:对应Rx-OVR,确认 Ring Buffer 溢出是否属实rx_fifo_errors:物理 FIFO 缓冲区满,多见于小包高吞吐场景,常与rx_over_errors同步上升rx_missed_errors:虚拟化环境关键指标,vCPU 调度延迟导致中断丢失,值上升即说明宿主机 CPU 过载或 vCPU 绑定不合理rx_dropped:包已入 Ring Buffer,但被内核协议栈丢弃,常见于net.core.netdev_max_backlog不足或软中断负载过高
别漏掉 tc/qdisc 的“静默丢包”
tc 规则造成的丢包完全不会出现在网卡统计里,是生产环境最常被误判的“幽灵丢包”:
- 运行
tc qdisc show dev eth0,重点找含netem、loss、policer、fq_codel的规则 - 加
-s参数看真实丢包数:tc -s qdisc show dev eth0,关注输出中dropped列是否持续增长 - 容器环境要扩展排查范围:CNI 插件(如 Calico、Cilium)常在
cali+或lxc+虚拟接口上挂 tc 规则,不能只查eth0
结合 netstat -s 看协议栈软件层丢包
netstat -s 统计的是协议栈**软件层**丢弃,和网卡硬件层的 dropped 不重叠。UDP 和 TCP 的关键字段含义差异很大:
- UDP:看
receive buffer errors(socket 接收缓存满)和packet receive errors(校验失败或端口无监听),后者高需先确认ss -uln | grep :端口 - TCP:别只盯
retransmits,timeouts持续上升更可能指向路由或防火墙拦截;estabresets突增大概率是应用主动 close,不是丢包 - 注意:
netstat -s是累计值,重启后清零——若只看单次输出,无法判断是否“正在发生”丢包
真正棘手的,从来不是看出哪个字段在往上跳,而是把字段变化和背后的硬件行为、调度约束一一对上号。比如 rx_missed_errors 持续上升,表面看像是驱动在报错,但根子上很可能是宿主机 CPU 超配,再叠加 vCPU 没有绑核;再比如 rx_dropped 偏高,单纯把 netdev_max_backlog 调大,很多时候只能缓一口气,未必解决问题,真正的症结可能是软中断线程长期吃不满一个 CPU 核。说到底,这些细节判断,往往比命令本身还关键。