文章目录
- DPDK 的设备环境搭建
- DPDK 如何才能正常运行
-
- 我们不禁要问什么是 DPDK ?
- DPDK环境的四大核心支柱
- DPDK 需要占据指定的网卡 (NIC, Network Interface Controller 网络接口控制器)
- DPDK 需要用户态地、“安全地” 直接访问硬件(UIO/VFIO 内存映射)
- DPDK 如果仍需内核协议栈的协助,那就得让内核协议栈看到网卡的浮影(KNI, Kernel NIC Interface 内核网卡界面)
- DPDK 需要霸占部分 CPU,并且需要这部分 CPU 只顾死盯巨页内存池(提高访问速度)
- 计算机的 NUMA / non-NUMA 架构
- DPDK 的巨页池(以内存空间换 CPU 的读取速度)
- 数据链路层究竟是什么?
- 新旧两个版本的 DPDK (19.08.2 vs 24.11.3)
推荐一个零声教育学习教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习: https://github.com/0voice 链接。
DPDK 的设备环境搭建
DPDK 可以提升服务器的吞吐量,却无法提升请求的处理速度 qps,也无法降低延迟。因为 CPU 还是那个 CPU,DPDK 只是改变了 CPU 的组合合作的方式提高数据收发速度,计算能力是没变过的。
什么是网卡(内含 DMA 控制器)?
网卡就像是电脑的 “翻译官” 或 “网络门户”。它负责将电脑内部的数字信号(0和1)转换成能在网线(或空气中)传输的信号,反之亦然。也就是说这是一个能将物理信息(电缆电频信号、光纤光信号、电磁频率信号)与数字模拟信号(二进制 0/1 信号)相互转换的设备。
网卡,全称网络接口卡,也称为网络适配器、网络接口控制器。它是计算机硬件的一部分,提供了连接到计算机网络的能力。
- 物理存在:它是一块实实在在的硬件。
- 形态:
- 集成网卡:现代主板通常都集成了有线网卡(那个插网线的接口)和无线网卡。
- 独立网卡:像显卡一样,可以插在 PCIe 插槽上,以提供更高级的性能或功能(如万兆网卡)。
- USB网卡:通过USB接口连接,常见于USB无线Wi-Fi接收器。
功能:实现网络通信所必需的物理层和数据链路层功能,如数据包的发送、接收、帧的构建、错误检查等。
功能:实现网络通信所必需的物理层和数据链路层功能,如数据包的发送、接收、帧的构建、错误检查等。
它基于 PCIe 与操作系统交互,她所需要做的工作如下.
-
发现与初始化:
- 系统启动时,BIOS/UEFI 和操作系统会扫描所有 PCI 总线。
- 操作系统读取每个 PCI 地址上设备的配置空间(一个标准的寄存器集),得知这里有一个“
Intel X710 10GbE网卡”,并为其分配资源(如内存映射地址、中断号)。
-
数据通信(DMA - 直接内存访问):
- 传统方式(需要CPU参与):CPU把要发送的数据从内存拷贝到网卡的缓冲区,然后命令网卡发送。效率低下。
- 现代方式(DMA):这是高性能的基石。
- 发包:CPU在内存中准备好数据,然后告诉网卡数据在内存中的地址。网卡作为一个PCI主设备,通过PCIe总线,主动发起DMA读取操作,直接从内存中抓取数据,然后发送。CPU只需下达指令,无需亲自拷贝数据。
- 收包:网卡收到数据包后,通过PCIe总线,主动发起DMA写入操作,直接将数据包写入内存中事先分配好的位置,然后通知CPU:“数据在某某地址,快来处理!”。
-
控制与状态(内存映射I/O - MMIO):
- 网卡的控制寄存器被映射到一段特定的物理内存地址。(命令 DMA 控制器向映射地址写本地寄存器里的内容)
- CPU要命令网卡“开始工作”、“开始接收”,只需像写普通内存一样,向这些映射地址写入指令即可。这被称为内存映射I/O。

什么是网卡驱动(它产生 sk_buff 结构体)?
网卡驱动就像是教操作系统(如Ubuntu)如何与网卡这个“翻译官”对话的“说明书”或“语言手册”。没有这本说明书,操作系统就算看到了网卡硬件,也不知道如何命令它工作。网卡(硬件)与网卡驱动(软件)的关系:
操作系统(Ubuntu) -> 通过【网卡驱动】这个翻译 -> 去命令和控制【网卡】这个硬件 -> 连接到网络。
驱动程序是一段特殊的软件代码,它是操作系统内核的一部分。它的作用是在硬件设备(如网卡)和操作系统以及更高层的应用程序之间建立一个桥梁,充当翻译官的角色。
- 功能:
- 向操作系统解释这个网卡是什么、有什么能力。
- 将操作系统的网络指令(如“发送这个数据包”)转换成网卡能理解的特定命令。
- 处理网卡接收到的数据,并将其整理好提交给操作系统。
- 重要性:没有正确的驱动程序,硬件就无法工作。这就是为什么有时新装的系统无法上网的原因——系统自带的驱动库中没有匹配你网卡硬件的驱动。
网卡驱动生产网络数据的万能容器 sk_buff
sk_buff 是内核网络协议栈的核心数据结构,是数据包在内核中的唯一化身。由 网卡驱动在收包时创建,并在协议栈中流转和变形。让我们追踪一个数据包被接收的完整流程,看看 sk_buff 的诞生:
-
网卡接收数据(物理层
->数据链路层)- 网卡通过物理线路接收到数据帧,通过DMA直接将其写入内核预留的环形缓冲区内存中。此时,这只是一块原始的、无组织的二进制数据,还没有
sk_buff。
- 网卡通过物理线路接收到数据帧,通过DMA直接将其写入内核预留的环形缓冲区内存中。此时,这只是一块原始的、无组织的二进制数据,还没有
-
网卡发出中断
- 网卡告诉CPU:“有数据到了,快来处理!”
-
驱动中断处理程序(
sk_buff的“诞生”)- 网卡驱动的中断处理程序被CPU调用。
- 这是最关键的一步:驱动程序分配一个新的
sk_buff结构体,然后根据网卡提供的描述符信息,让这个sk_buff的指针指向DMA缓冲区中的那份原始数据。 - 此时,
sk_buff就像一个空的面单被贴到了一个现成的货箱上。驱动会填充最基础的信息,比如数据长度、到达的网卡接口等。
-
送入协议栈(sk_buff 的“旅程”)
- 驱动将这个新生的
sk_buff送入内核的网络协议栈。 - 向上传递:
sk_buff从数据链路层开始,依次经过网络层(IP)、传输层(TCP/UDP)。 - “撕面单”:每经过一层,该层的协议处理代码就解析并移除相应的协议头(如以太网头、IP头)。这是通过移动
sk_buff内部的指针实现的,避免了昂贵的数据拷贝,效率极高。 - “贴新面单”:发送数据时过程相反,各层协议在数据前面添加自己的协议头。
- 驱动将这个新生的
-
交付应用程序
- 最终,剥离了各种协议头的纯净数据(Payload)被存放在
sk_buff中,通过socket接口传递给用户态应用程序(如nginx, curl)。
- 最终,剥离了各种协议头的纯净数据(Payload)被存放在
发送过程则是逆向的:应用程序的数据通过socket发出,内核为其创建 sk_buff,各层协议不断添加头部,最终由驱动将 sk_buff 中的数据通过网卡发送出去。
struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;
/* ... */
// 指向整个数据缓冲区的指针(整个“集装箱”的起始地址)
unsigned char *head;
unsigned char *data; // 指向当前协议数据的起始位置(“货物”的起始地址)
unsigned char *tail; // 指向当前协议数据的结束位置
unsigned char *end; // 整个数据缓冲区的结束地址
// 当前数据长度(从 data 到 tail 的长度)
unsigned int len;
// 整个缓冲区的总长度(从 head 到 end 的长度)
unsigned int truesize;
// 协议栈信息
__u32 priority; // 包优先级 (QoS)
__be16 protocol; // 从L2头解析出的协议 (e.g. ETH_P_IP)
__u16 pkt_type; // 包类型 (单播, 组播, 广播...)
// 网络设备信息
struct net_device *dev; // 接收或发送该skb的网络设备
// 套接字信息
union {
struct sock *sk; // 与之关联的socket
};
// 控制缓冲区 (cb)
char cb[48]; // 各层协议的私有信息存储空间
/* ... */
};
什么是多队列网卡?
要理解多队列网卡,我们最好先看看它的前身——单队列网卡。
- 单队列网卡的瓶颈:
在单队列网卡中,所有收到的数据包都放在一个单一的接收队列中。当数据包到达时,网卡会向CPU发出一个硬件中断请求,通知CPU:“有数据来了,快来处理!”。- 问题:这意味着无论网络流量多大,都只由一个CPU核心来处理所有这些网络数据包。
- 比喻:就像一个餐厅只有一个服务员。所有顾客的点单、上菜、结账都由这一个人完成。当顾客非常多时,这个服务员就会成为瓶颈,忙得不可开交,而其他服务员却闲着无事可做。这个唯一的服务员就是那个唯一的CPU核心。
随着网络速度的提升(千兆、万兆、甚至更高),单个CPU核心很容易被网络中断处理完全占满,导致系统性能下降,无法处理实际的应用任务(如计算、数据库查询等)。这就是所谓的 “中断风暴”。
- 多队列网卡的解决方案:
多队列网卡的出现就是为了解决这个瓶颈。- 核心思想:它将数据包处理工作分散到多个CPU核心上。
- 如何实现:
- 多个队列:网卡硬件上拥有多个独立的接收和发送队列。
- 流量分发:当一个网络数据包到达时,网卡会根据一个哈希算法(例如,基于源/目的IP地址和端口号)来决定这个数据包应该放入哪个队列。
- 多核处理:每个队列都有自己的中断请求线,可以独立地中断不同的CPU核心。CPU核心A处理队列1的数据,CPU核心B处理队列2的数据,以此类推。
- 比喻:现在餐厅雇了多个服务员(多个CPU核心)。领班(网卡硬件)根据顾客的特征(比如按桌号奇偶性)将新来的顾客分组,然后分配给不同的服务员。每个服务员只为自己负责的几桌顾客服务。这样工作效率大大提高,避免了单个服务员过载的情况。
多队列网卡的优点:
- 提升性能:充分利用多核CPU的处理能力,显著提高网络吞吐量。
- 减少延迟:数据包可以被更快地处理,因为等待时间变短了。
- 降低单CPU负载:避免了单个CPU核心被网络中断100%占满的问题。
也就是说,做 “多重影分身” 之术,分出多个 CPU 去执行系统内核的 IO 操作,这会极大提升了我们的 IO 性能,之前我们所做的 reactor 网络模型的速度会得到质的飞跃。
那如何才能知道自己主机(虚拟机)的网卡是否为多队列网卡呢?最可靠的方法是查看中断号分布。每个队列都会产生自己的中断,通过查看中断(IRQ)在不同CPU核心上的分布情况,可以推断出多队列的工作状态。
qiming@qiming:~$ cat /proc/interrupts | grep ens33
19: 0 0 41 1560800 IO-APIC 19-fasteoi ens33
这行 BASH 命令行的输出里面,每一项都是有意义的。
| IRQ 号 | CPU_1 | CPU_2 | CPU_3 | CPU_4 | 中断类型 | 硬件信息 | 设备名 |
|---|---|---|---|---|---|---|---|
| 19: | 0 | 0 | 41 | 1560800 | IO-APIC | 19-fasteoi | ens33 |
这若干项的具体含义如下
| 列号 | 名称 | 说明 |
|---|---|---|
| 第1列 | IRQ 号 | 对应这条中断线的全局编号(示例 19) |
| 第2…5列 | CPU_1 计数 CPU_2 计数 … | 每个 CPU 核自开机以来收到该中断的次数;有几核就有几列 |
| 倒数第3列 | 中断类型 | IO-APIC 是 x86 平台专用的“中断路由器”芯片/模块,用来把 键盘、网卡、磁盘等外设的中断信号 收集起来,再按 可编程规则 分发给 哪个 CPU 核、什么优先级、边缘还是电平触发。 |
| 倒数第2列 | 硬件信息 | 19-fasteoi 表示 第 19 号中断线采用 “快速 EOI” 路径通知 APIC“已处理完” ,而且是一条电平触发(Level-triggered)中断; |
| 最后1列 | 设备名 | ens33 即网卡队列的成员,如此可见这只是一个单队列网卡 |
以上现象,都在呼唤我们要重新设定一个网卡,我们要做提升网络 IO 效率的准备了,我们要升级设备了!!!
给虚拟机配置一块多队列网卡(vmxnet3)
首先,我们得确保自己的虚拟机上有 open-vm-tools 这个软件。以下的输出表示这个软件存在。
qiming@qiming:~$ systemctl status open-vm-tools
● open-vm-tools.service - Service for virtual machines hosted on VMware
Loaded: loaded (/lib/systemd/system/open-vm-tools.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2025-09-10 12:04:41 UTC; 2h 4min ago
Docs: http://open-vm-tools.sourceforge.net/about.php
Main PID: 721 (vmtoolsd)
Tasks: 3 (limit: 9346)
Memory: 9.4M
CPU: 14.473s
CGroup: /system.slice/open-vm-tools.service
└─721 /usr/bin/vmtoolsd
Sep 10 12:04:41 qiming systemd[1]: Started Service for virtual machines hosted on VMware.
open-vm-tools 是 VMware 官方开源的“虚拟机增强工具包”,相当于 Linux/FreeBSD 等系统里的 VMware Tools 替代品。它运行在 客户机操作系统内部,通过一组守护进程、内核模块和桌面插件,把宿主机(ESXi / Workstation / Fusion)提供的虚拟化接口转成 时钟、剪贴板、分辨率、文件共享、心跳 等实用功能。不过,在此处最重要的功能是,open-vm-tools是有 vmxnet3 所需的驱动模块。vmxnet3 是什么来的?网卡型号!什么网卡?多队列网卡! 我现在的网卡型号是 e1000,网卡的接口名是 ens33 ,可是这只是一个单队列网卡。 open-vm-tools 拥有着 e1000、vmxnet3 网卡的驱动软件。
为了给虚拟机配置新的网卡,我们先关机,并且在虚拟机文件所在的文件夹里找到一个 .vmx 文件。这个 .vmx 文件是 VMware 虚拟机的配置文件,它定义了虚拟机的所有硬件设置和运行参数。你可以把它看作是虚拟机的“蓝图”或“清单”。

我们打开这个文件,发现它是一个 KEY-VALUE 型的文本文件。其中可分为以下几类
-
核心硬件资源
numvcpus = "4": 为虚拟机分配 4 个虚拟 CPU 核心。cpuid.coresPerSocket = "1": 将这4个核心呈现为 4个单独的CPU插座(Socket)。这通常是为了兼容某些操作系统或软件的许可要求。memsize = "8192": 为虚拟机分配 8192 MB(即 8 GB) 的内存。mem.hotadd = "TRUE"和vcpu.hotadd = "TRUE": 允许在虚拟机开机运行时动态添加内存和CPU(需要客户机操作系统支持,如 Linux)。
-
磁盘与光驱
scsi0:0.fileName = "Ubuntu-N1.vmdk": 虚拟机的主硬盘使用的是名为Ubuntu-N1.vmdk的虚拟磁盘文件。sata0:1.fileName = "D:\VisualMachine\ubuntu-22.04.1-live-server-amd64.iso"和sata0:1.present = "TRUE": 虚拟机的 SATA 光驱连接了一个 ISO 镜像文件(Ubuntu 22.04 的安装镜像)。这通常用于安装系统或加载工具盘。
-
网络适配器
ethernet0.virtualDev = "e1000": 虚拟网卡的硬件类型被模拟为 Intel E1000。这是一种非常常见且兼容性好的网卡型号,大多数操作系统都自带其驱动。ethernet0.connectionType = "nat": 虚拟网卡的连接方式为 NAT 模式。这意味着虚拟机共享主机的IP地址上网,外部网络无法直接访问虚拟机,但虚拟机可以访问外部网络。这是最简单安全的默认网络模式。ethernet0.present = "TRUE": 该网络适配器已启用。ethernet0.generatedAddress = "00:0c:29:04:18:ec": VMware 自动为虚拟机生成的 MAC 地址。
-
显示与图形
svga.vramSize = "268435456": 为虚拟显卡分配 256 MB 的显存。mks.enable3d = "TRUE": 启用了 3D 图形加速功能,这对于运行图形界面(如 Ubuntu Desktop)的体验至关重要。
-
虚拟机基本信息
displayName = "Ubuntu-N1"</

最低0.47元/天 解锁文章
2528

被折叠的 条评论
为什么被折叠?



