为什么我的 DPDK 程序 CPU 很高,却几乎没有流量?一次排查让我彻底理解 busy polling
我刚开始做DPDK开发时,第一次看到程序运行状态,都会被一个现象吓到:
CPU 100%
而且:不是一个核。
而是:所有 lcore 全部 100%
更奇怪的是:即使没有任何流量。CPU 依然满载。
第一次遇到这个问题时,我甚至怀疑:
- 程序死循环?
- 某处卡死?
- 网卡异常中断?
- rte_ring 有 bug?
- worker 空转?
但后来我才意识到:这不是 bug。
而是 DPDK 最核心的设计哲学之一:busy polling
也叫:polling mode
而真正理解它之后,我才明白为什么 DPDK 能做到千万 PPS。
一、问题现场
当时写了一个简单收包程序:
核心代码:
while (1) {
nb_rx = rte_eth_rx_burst(port, qid, pkts, 32);
for (i = 0; i < nb_rx; i++) {
process(pkts[i]);
}
}
程序启动后:
即使没有任何流量:
top -H
依然显示:
100% CPU
二、第一反应:是不是死循环
因为:代码看起来确实像:
while(1)
无限循环。
于是很多新手第一反应:加 sleep。
例如:
usleep(1);
CPU 瞬间下降。
但:吞吐也直接崩了。
三、为什么加 sleep 会严重掉性能
因为:DPDK 最核心的思想是:主动轮询网卡。
而不是:等待网卡通知。
四、传统 Linux 网络模型
普通 Linux 网络栈:
数据到达时:
NIC
↓
interrupt
↓
kernel wakeup
↓
softirq
↓
socket
即:中断驱动。CPU 平时可以休息。
五、DPDK 完全不同
DPDK 使用:DPDK Poll Mode Driver
即:PMD(Poll Mode Driver)
工作方式:
while(1)
check_rx_queue();
不断轮询。
六、为什么轮询反而更快
很多人第一次听到会很奇怪:
不停空转:怎么会更高效?
其实关键在于:避免中断开销。
七、中断其实很“贵”
一次网络中断:
涉及:
- interrupt entry
- context switch
- scheduler
- cache pollution
- softirq
代价很高。
八、尤其在高 PPS 场景
假设:10 Mpps
即:每秒:1000 万包
如果每个包都触发中断:
系统直接崩溃。
九、Linux 为什么会出现 softirq 风暴
因为:
高流量下:CPU 会持续处理中断。
导致:ksoftirqd CPU 100%
这也是传统协议栈的瓶颈之一。
十、DPDK 的核心思想
既然高流量下:CPU 本来就没法休息。
那不如:不要中断。
直接让CPU 永远盯着 RX queue
这样:包一到立刻处理。
十一、这就叫 busy polling
即:CPU 持续轮询硬件。
十二、为什么它性能极高
因为:避免了:
1. 中断切换
2. scheduler 调度
3. 内核唤醒
4. cache miss
CPU cache 始终保持热状态。
十三、cache locality 才是真正关键
DPDK 的高性能核心之一:不是“用户态”。
而是:cache-friendly pipeline。
例如:连续轮询:
RX descriptor
mbuf
ring
flow table
cache 命中率极高。
十四、为什么 idle 时 CPU 仍然 100%
因为:CPU 正在:不停读取 RX queue
即使:没有包。循环仍然存在。
十五、一个典型误区
很多人看到:
CPU 100%
就认为:系统已经满载。
其实:DPDK 中:
CPU busy != CPU overloaded
可能只是:polling。
十六、真正需要关注什么
不是:
CPU usage
而是:
cycles per packet
cache miss
queue depth
latency
十七、为什么 DPDK 程序通常独占 CPU
因为:busy polling 必须:长时间占用核心。
所以:生产环境通常:
isolcpus
taskset
NUMA binding
全部安排上。
十八、进一步理解 PMD
PMD 全称:Poll Mode Driver
即:轮询模式驱动。
本质:CPU 主动“问”网卡:
“有没有包?”
“有没有包?”
“有没有包?”
而不是:网卡中断通知。
十九、为什么小流量场景下 DPDK 反而不划算
因为:
即使:
0 packet
CPU 也在满速轮询。
功耗极高。
二十、这也是为什么 DPDK 更适合
高频交易
UPF
vSwitch
DPI
运营商城关
这些:高 PPS 场景。
二十一、有没有办法降低 idle CPU
有。
DPDK 提供:
power management
以及:
rte_pause();
等机制。
二十二、rte_pause 的作用
例如:
while (1) {
nb_rx = rte_eth_rx_burst(...);
if (nb_rx == 0) {
rte_pause();
continue;
}
}
可以降低:pipeline 压力。
二十三、为什么不能直接 sleep
因为:sleep 会导致:
scheduler 介入
cache 冷却
wakeup latency
恢复成本巨大。
二十四、另一个重要知识:polling latency 更稳定
中断模式:
会有:
interrupt coalescing
即:攒包中断。
导致:latency jitter。
而 busy polling:
通常:
tail latency 更稳定
这也是很多低时延系统选择 DPDK 的核心原因。
二十五、一次真实测试
当时做过实验:
interrupt mode
平均 RTT:
80us
但:P99:
2ms
busy polling
平均 RTT:
40us
P99:
60us
稳定很多。
二十六、进一步理解“CPU 100%”
其实:DPDK 中:CPU 100% 更像:核心被专用化。
即:这个核心已经成为:网络数据平面处理器。不再是通用 CPU。
二十七、为什么很多人第一次接触 DPDK 会不适应
因为传统开发习惯:
省 CPU
event-driven
epoll
interrupt
而 DPDK:完全相反:
dedicate core
busy polling
lockless
cache-first
这是两种完全不同的设计哲学。
二十八、这次排查真正学到什么
以前我以为:高性能网络就是:更快的 socket。
后来才意识到:DPDK 本质上是在:用 CPU 换 latency 和 throughput。
它牺牲:
- CPU 空闲率
- 功耗
- 通用性
换取:
- 极低时延
- 极高吞吐
- 更稳定 tail latency
二十九、总结
为什么 DPDK 程序没有流量时 CPU 仍然 100%?
因为:DPDK 使用 busy polling。
CPU 始终在主动轮询网卡。
通过这个问题,我们真正理解了:
核心概念
- PMD
- busy polling
- interrupt vs polling
- cache locality
- softirq
- tail latency
很多时候,DPDK 真正颠覆的不是 API。
而是:整个网络系统的设计思想。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)