sk_buff队列本身不可调,真正影响丢包的是网卡ring buffer、netdev_max_backlog软中断队列和socket接收队列三层缓冲;ring buffer溢出表现为ethtool -s eth0中rx_missed_errors持续上涨,且该值非零即为铁证。

sk_buff 队列本身不是可调的“队列长度”,真正影响丢包的是它所依赖的几层缓冲区:网卡 Ring Buffer、内核软中断处理队列(netdev_max_backlog)、以及 socket 接收队列(sk_receive_queue)。所谓“sk_buff 队列太短”,其实是这些环节中某一层被填满后,新 sk_buff 无法分配或入队,导致丢弃。
怎么确认是 Ring Buffer 溢出导致的丢包
网卡 DMA 写包时若 Ring Buffer 满,硬件直接丢弃,不进内核协议栈——这是最典型的“看不见的丢包”。关键指标不是 ifconfig 的 overruns,而是驱动级计数器:
-
ethtool -S eth0 | grep rx_missed_errors非零且持续上涨 → Ring Buffer 真的不够用 -
ethtool -g eth0查看当前 RX 值(如Current hardware settings: RX: 256) - 注意:
rx_missed_errors和rx_over_errors不同,后者多为 CRC 错误,前者才是 Ring Buffer 溢出的铁证
调大 Ring Buffer 后为什么还丢包
增大 ethtool -G eth0 rx 4096 只解决第一跳,后面两关必须同步跟上,否则瓶颈前移:
-
net.core.netdev_max_backlog必须 ≥ Ring Buffer 大小,否则软中断队列溢出,netstat -s | grep "packet receive errors"会涨 -
net.core.rmem_default和net.core.rmem_max要匹配业务吞吐,UDP 场景尤其敏感;netstat -s | grep UdpInOverflows上涨说明 socket 层已溢出 - 别忽略 CPU 软中断分布:
cat /proc/interrupts | grep eth0若单核 softirq 占用长期 >85%,需启用 RPS 或调整 RSS 队列绑定
sk_buff 分配失败的典型现象与验证
当内存紧张或 slab 分配器压力大时,alloc_skb() 可能返回 NULL,此时丢包发生在 netif_receive_skb() 入口之前,日志里看不到包,但内核统计会体现:
-
grep "skb_alloc" /proc/kmsg(需先dmesg -n 8提高日志级别) -
cat /proc/slabinfo | grep skbuff_head_cache查看num和active差值过大,说明缓存碎片化严重 -
vmstat 1观察pgpgin/pgpgout是否突增,结合slabtop看skbuff_head_cache的use是否接近max
真正难缠的不是参数调不对,而是问题横跨三层缓冲:Ring Buffer 溢出、netdev_max_backlog 滞后、socket 队列又满——三者叠加时,ethtool -S 和 netstat -s 的计数器会互相掩盖真实瓶颈点。务必按接收路径顺序逐层验证,别只盯着一个数字猛调。











