一次RX Mbuf耗尽引发的DPDK性能雪崩——彻底理解DPDK RX Refill机制与Descriptor Ownership(上)
一、一次诡异的100G性能故障某运营商部署了一套基于DPDK开发的100G核心交换设备。系统已经稳定运行半年。整体架构采用Poll Mode DriverPMDRun-to-CompletionRTCRSS多队列每队列绑定独立WorkerHugePageNUMA绑定上线后的长期性能如下指标数值吞吐98.2GbpsCPU100%RX Drop0TX Drop0Packet Loss0某天业务高峰期间监控突然报警指标故障时吞吐12.6GbpsCPU100%RX Drop暴涨TX Drop0LinkUp最奇怪的是网卡没有任何Error、没有CRC、没有DMA Fault、没有PCIe异常。设备看起来一切正常。但是数据包就是收不上来了。二、第一轮排查是不是CPU处理不过来第一反应当然是CPU。查看perf stat得到指标数值IPC1.82Cycles正常Instructions正常Cache Miss正常CPU依然100%。IPC没有下降。说明CPU一直在正常执行。不是CPU瓶颈。三、第二轮排查是不是PCIe带宽不足继续检查PCIe。查看NIC统计ethtool -S发现RX DMA Error 0PCIe Correctable Error 0PCIe Replay 0DMA没有异常。PCIe没有重传。链路正常。上一篇文章讨论过的PCIe瓶颈。这一次也排除了。四、真正异常的是RX No Buffer继续查看网卡统计突然发现一个平时没人关注的计数器rx_no_buffer开始疯狂增加0 ↓ 184 ↓ 12083 ↓ 328741终于真正的问题出现了。很多工程师第一次看到这个计数器都会疑惑网卡不是还有RX Ring吗为什么会No Buffer五、很多人误解了RX Ring很多人认为RX Ring里面放的是Descriptor其实只说对了一半。真正放进去的是指向mbuf的Descriptor。也就是说每一个RX Descriptor都必须提前绑定一个空闲mbuf。真正结构如下RX Descriptor 0 --- mbuf0 RX Descriptor 1 --- mbuf1 RX Descriptor 2 --- mbuf2 ... RX Descriptor N --- mbufNNIC收到数据包以后DMA不会自己申请内存。它只能按照Descriptor里面保存的DMA地址直接写入。所以没有mbuf就没有地方DMA。六、RX Descriptor到底归谁这是DPDK收包过程中最容易被忽略也是最重要的一个概念Descriptor Ownership所有权Descriptor并不是一直属于NIC。它的所有权会不断切换。整个生命周期如下PMD初始化 ↓ 填充mbuf ↓ Ownership NIC ↓ NIC DMA写入数据 ↓ DD位置1 ↓ Ownership CPU ↓ PMD读取数据 ↓ CPU处理数据 ↓ 重新放入新的mbuf ↓ Ownership NIC注意整个过程中Descriptor本身几乎不会重新分配。真正不断变化的是Descriptor后面绑定的mbuf。七、为什么PMD收到包以后不会立即把mbuf放回去很多新人第一次看PMD源码都会产生疑问既然包已经收到了。为什么不马上rx_desc-buffer new_mbuf;这样RX Ring不是一直都有Buffer实际上如果每收到一个包就重新申请一个mbuf。意味着每个包都要执行mempool alloc ↓ 更新Descriptor ↓ Memory Barrier ↓ 更新Tail100G64Byte包意味着每秒接近1.49亿个数据包。如果每个包都执行一次Descriptor更新。CPU几乎全部时间都浪费在维护RX Ring。而不是处理数据。八、真正的秘密批量RearmIntel所有PMD。几乎都采用同一个思想Batch Rearm批量补充也就是说。收到一个包不会立即补一个。而是累计例如32个或者64个一起补充。流程变成收32个包 ↓ 一次申请32个mbuf ↓ 一次更新32个Descriptor ↓ 一次Memory Barrier ↓ 一次更新RX Tail整个过程Descriptor更新次数立即下降32倍。九、为什么源码里面总能看到rx_free_thresh很多人第一次阅读ice_rx.c或者ixgbe_rxtx.c都会看到rx_free_thresh很多人认为这是释放Threshold。其实完全不是。它真正代表的是什么时候开始批量补充RX Buffer。例如Ring 1024已经消费31个。继续收。继续处理。直到消费32个。此时PMD才开始统一Rearm。也就是说。rx_free_thresh控制的不是释放而是Rearm时机。十、为什么No Buffer会导致RX Drop到这里很多人已经明白Descriptor必须绑定mbuf。那么如果PMD没有及时Rearm。就会出现RX Descriptor ↓ Buffer NULLNIC收到新包准备DMA却发现没有Buffer。DMA无法开始。于是NIC只能直接丢弃。这就是RX No Buffer真正含义。注意。这不是软件主动Drop。而是硬件没有可写入的数据缓冲区。因此很多现场都会看到RX Drop ↑ NIC Error 0因为NIC根本没有坏只是没有地方存包。未完待续