Netpath
学习路径33 / 49 · 高性能网络看全程 →
原理深入预计 30 分钟

DPDK:用户态轮询与大页内存

把网卡从内核手里抢过来自己轮询,换来极低延迟和整核的 CPU 占用。

学完这节你能做到

  • 解释轮询模式驱动为什么比中断快
  • 列出 DPDK 的部署前提与资源代价
  • 判断该选 DPDK 还是 XDP 还是 RDMA

建议先学

跳过这几节会看不懂本节的部分推导

把网卡从内核手里抢过来

L0 讲过收包路径:DMA → 硬中断 → 软中断 NAPI → 协议栈 → socket。 每一步都有开销,而且中断本身在高 PPS 下就是负担。

DPDK 的做法很极端:让内核完全放弃这张网卡,用户态程序自己轮询它。

内核路径:  网卡 → 中断 → 软中断 → 协议栈 → 拷贝到用户态
DPDK:      网卡 → 用户态程序直接轮询读取     ← 没有中断、没有协议栈、没有拷贝

PMD:为什么轮询比中断快

反直觉的一点:忙等(轮询)居然比事件通知(中断)更高效。

原因是中断在高频场景下代价太大:

中断的开销说明
上下文切换保存/恢复现场
缓存污染打断正在跑的代码,CPU 缓存失效
调度延迟软中断要等 CPU 调度

包速率低时中断是划算的(空闲时不占 CPU)。但在每秒千万包的量级, 中断的固定开销乘以包数就变成了主要成本。

PMD(Poll Mode Driver)干脆不用中断:一个 CPU 核死循环读网卡队列。

while (1) {
    nb_rx = rte_eth_rx_burst(port, queue, bufs, BURST_SIZE);
    /* 处理这一批包 */
}
!代价:那个核 100% 占用,永远

PMD 核在 top 里永远是 100%,无论有没有流量。这不是 bug,是设计。

后果要提前想清楚:

  • CPU 账要重算:跑 4 个 PMD 核就是 4 个核永久不可用于业务
  • 监控告警要排除这些核,否则天天报 CPU 高
  • 云上按核计费时,这笔成本很显性

三个必须满足的前提

① 大页内存

DPDK 用大页(HugePage)而不是常规 4KB 页,为的是减少 TLB miss:

4KB 页:  1 GB 内存 = 262144 个页表项 → TLB 频繁失效
2MB 大页:1 GB 内存 = 512 个页表项    → TLB 命中率大幅提升
# 分配大页
echo 2048 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# 或者启动参数(推荐,避免内存碎片后分配失败)
# default_hugepagesz=1G hugepagesz=1G hugepages=8

# 确认
grep -i huge /proc/meminfo
mount | grep hugetlbfs

大页要在系统启动早期分配——运行久了内存碎片化,可能分不出连续的大页。

② 设备绑定到 VFIO/UIO

要让用户态直接访问网卡,得先把它从内核驱动上解绑:

# 看当前绑定状态
dpdk-devbind.py --status

# 绑到 vfio-pci(推荐,有 IOMMU 保护)
modprobe vfio-pci
dpdk-devbind.py --bind=vfio-pci 0000:31:00.0

# 解绑回内核驱动
dpdk-devbind.py --bind=mlx5_core 0000:31:00.0
Network devices using DPDK-compatible driver
============================================
0000:31:00.0 'MT2892 Family' drv=vfio-pci unused=mlx5_core

Network devices using kernel driver
===================================
0000:31:00.1 'MT2892 Family' if=ens1f1 drv=mlx5_core unused=vfio-pci

绑定之后这张卡在 ip link 里就消失了——它已经不属于内核。

驱动说明
vfio-pci推荐,用 IOMMU 做内存隔离,更安全
uio_pci_generic老方案,无 IOMMU 保护
igb_uioDPDK 自带,同样无 IOMMU

③ CPU 独占与 NUMA 亲和

PMD 核要独占,不能被内核调度器打扰:

# 内核启动参数:把这些核从调度器手里隔离出来
# isolcpus=2-9 nohz_full=2-9 rcu_nocbs=2-9

# 确认网卡属于哪个 NUMA 节点
cat /sys/bus/pci/devices/0000:31:00.0/numa_node
lscpu | grep NUMA

PMD 核、大页内存、网卡必须在同一个 NUMA 节点上—— 跨 NUMA 访问的代价(PCIe 那节 讲过)会吃掉大部分收益。

最大的代价:常规工具全部失效

这一条要单独强调,因为它直接决定了运维方式:

ip link show          # 看不到这张卡
ethtool -S ens1f0     # 设备不存在
tcpdump -i ens1f0     # 抓不到任何东西
ss -s                 # 与这张卡无关
iptables              # 完全不经过

L0 教的那整套排障方法,在 DPDK 网卡上一条都用不了。

替代手段全部来自应用自己:

需求DPDK 侧的做法
看统计应用暴露的计数器(rte_eth_stats_get)
抓包dpdk-pdump,且应用要编译时支持
看队列状态应用自己实现的管理接口
监控应用主动上报,没有通用 exporter
×上 DPDK 等于把运维责任转移给了应用

这是选型时最容易低估的一点。之前"网络出问题看 ethtool -S"是通用能力, 现在能不能排障完全取决于这个应用实现了多少可观测接口。

如果是自研应用,这部分工作量要算进去;如果是第三方产品, 上线前一定要验证它的可观测能力——否则出问题时你只能重启。

什么场景真的需要它

DPDK 的定位很清晰:每个包都要做复杂的用户态处理,且要跑到极致 PPS。

场景适合吗
网关 / NFV(虚拟路由器、防火墙、CGNAT)✅ 天生适合
专用负载均衡器✅
高频交易的极低延迟✅
通用服务器要提升吞吐❌ 用 RSS / 多队列 / 巨帧就够
K8s 节点想加速❌ 用 eBPF/XDP,别夺走网卡
存储或 AI 集群❌ 用 RDMA,它同时解决延迟与 CPU

和 XDP、RDMA 的关系

三条"绕开内核"的路线,各自解决不同问题:

XDPDPDKRDMA
位置内核驱动层用户态硬件
网卡独占否是否
CPU 参与搬运是是(还要轮询)否
常规工具可用失效部分失效
适合高速丢弃/转发复杂包处理大块传输、低延迟

关键区别:DPDK 仍然要 CPU 搬每一个包(只是搬得更高效), 而 RDMA 让网卡直接读写内存,CPU 完全不参与 (为什么需要 RDMA 那节讲过)。

所以数据密集型场景(存储、AI)选 RDMA,包处理密集型场景(网关)选 DPDK。

✓决策顺序:从代价小的开始
性能不够
  ├─ 先做常规优化:多队列 RSS、中断亲和、巨帧、offload   ← L0 那一节
  ├─ 还不够 → eBPF/XDP(不夺网卡、工具还能用)
  ├─ 是大块传输或延迟敏感 → RDMA
  └─ 是每包复杂处理且要极致 PPS → DPDK

大多数"性能不够"在第一步就解决了。 L0 闯关那台机器的问题 (多队列只开了 1 个)就是典型——上 DPDK 也救不了配置错误。

检查点

Checkpoint单选

DPDK 的 PMD 核在 top 里永远显示 100% CPU。这说明什么?

Checkpoint单选

网卡绑定到 vfio-pci 之后,ethtool -S 和 tcpdump 都用不了。为什么?

Checkpoint单选

AI 训练集群想降低通信延迟、减少 CPU 开销。该选哪条路线?

这节课的落点

  • DPDK = 内核放弃网卡,用户态轮询:没有中断、没有协议栈、没有拷贝
  • 轮询在高 PPS 下胜过中断,代价是 PMD 核永久 100% 占用
  • 三个前提:大页内存(启动早期分配)、VFIO/UIO 绑定、CPU 独占 + NUMA 亲和
  • 绑定后网卡从 ip link 消失,ethtool/tcpdump/iptables 全部失效
  • 可观测性完全转移给应用——第三方产品上线前必须验证这一点
  • 适合网关、NFV、专用 LB、高频交易;不适合通用服务器、K8s 节点、存储与 AI 集群
  • 与另两条路线的分工:XDP 丢弃转发、DPDK 每包复杂处理、RDMA 大块低延迟
  • 决策顺序:常规优化 → eBPF/XDP → RDMA → DPDK,多数问题第一步就解决了

延伸资料

  • Systems Performance, 2nd Edition — Brendan Gregg