DPDK、TC 和 XDP:Linux 高性能网络到底在优化什么

DPDK、TC 和 XDP:Linux 高性能网络到底在优化什么

在看 Linux 高性能网络、软路由、负载均衡或者网络性能优化时,经常会看到几个词:

text 复制代码
DPDK
TC
XDP
eBPF
Kernel Bypass
Zero Copy

刚开始接触时,很容易把 DPDK、TC 和 XDP 当成三个互相竞争的技术。

但实际上它们解决的问题并不完全一样。

如果先给一个比较粗的理解:

text 复制代码
TC
主要在 Linux 网络协议栈内部做流量控制和数据包处理

XDP
尽可能早地在网卡收到数据包时进行处理

DPDK
直接绕开 Linux 内核网络协议栈,由用户态程序接管数据包

它们之间最关键的区别,其实是:

数据包到底在网络路径的哪个位置被处理。


1. 先看普通 Linux 网络路径

先不考虑 DPDK、TC 和 XDP。

假设网卡收到一个数据包,普通 Linux 网络路径可以粗略理解成:

text 复制代码
NIC
 |
DMA
 |
Driver
 |
Linux Kernel
 |
Network Stack
 |
TCP / UDP
 |
Socket
 |
Application

例如一个普通的 TCP Server:

cpp 复制代码
int fd = socket(...);

bind(fd, ...);

listen(fd, ...);

accept(fd, ...);

recv(fd, ...);

应用程序最终通过 Socket 接收数据。

在这个过程中,数据包需要经过:

text 复制代码
网卡
↓
网卡驱动
↓
Linux 网络协议栈
↓
IP
↓
TCP / UDP
↓
Socket
↓
用户程序

这种方式最大的优点就是简单。

Linux 已经帮我们完成了:

text 复制代码
路由
TCP
UDP
拥塞控制
重传
防火墙
Socket
网卡驱动

应用程序只需要使用 Socket API。

但是对于一些极端高性能场景来说,这条路径里面存在不少额外开销。

例如:

text 复制代码
中断处理
协议栈处理
skb 分配和释放
上下文切换
内核态 / 用户态切换
Cache Miss
数据结构遍历

单个数据包看起来没什么。

但假设服务器每秒需要处理:

text 复制代码
10M packets
20M packets
甚至更高

这些开销就会被不断放大。

所以高性能网络优化的一个核心思想就是:

能不能让数据包少走一点路?

TC、XDP 和 DPDK,本质上都是围绕这个问题展开的。


2. TC 是什么

TC 全称:

text 复制代码
Traffic Control

也就是 Linux 的流量控制系统。

很多人第一次看到 TC,可能是在这样的命令里:

bash 复制代码
tc qdisc

或者:

bash 复制代码
tc filter

传统上,TC 主要用于:

text 复制代码
限速
流量整形
队列管理
QoS
丢包模拟
延迟模拟

例如可以人为给网卡增加 100ms 延迟:

bash 复制代码
tc qdisc add dev eth0 root netem delay 100ms

也可以限制带宽。

但后来随着 eBPF 的发展,TC 不只是做简单的流量控制了。

我们还可以把 eBPF 程序挂到 TC 上。

例如:

text 复制代码
NIC
 |
Driver
 |
Linux Network Stack
 |
TC ingress
 |
...
 |
TC egress
 |
Driver
 |
NIC

TC 主要有两个比较重要的位置:

text 复制代码
ingress
egress

也就是:

text 复制代码
数据包进入主机

数据包离开主机

因此可以在这些位置做:

text 复制代码
包过滤
包统计
修改 Header
流量分类
重定向
限速
网络监控

例如做一个简单的网络监控程序:

text 复制代码
eth0
 |
TC ingress
 |
eBPF Program
 |
统计 src IP
统计 dst IP
统计 bytes
统计 packets

这样就可以直接在内核网络路径中统计流量。

TC 的一个特点是:

它仍然工作在 Linux Kernel Network Stack 体系里面。

也就是说,它并没有绕开 Linux 内核。


3. TC eBPF 的基本位置

假设一个包进入 Linux:

text 复制代码
NIC
 |
Driver
 |
XDP
 |
skb
 |
TC ingress
 |
Routing / TCP / UDP
 |
Socket
 |
Application

这里可以看到:

TC 的执行位置已经比较靠前。

但它还是晚于 XDP。

一个比较关键的原因是:

TC 通常处理的是已经转换成 sk_buff 的数据包。

Linux 网络协议栈里面有一个非常核心的数据结构:

cpp 复制代码
struct sk_buff

也经常简称:

text 复制代码
skb

Linux 会使用 skb 描述一个网络数据包。

里面包含:

text 复制代码
数据地址
数据长度
协议类型
网卡信息
路由信息
Header 信息
各种 Metadata

它非常强大。

但强大的代价就是:

它比较重。

如果我们只是想判断:

text 复制代码
这个包要不要丢

却先构造一个完整 skb,然后再处理,就可能有一些额外开销。

所以 XDP 的设计思路就是:

能不能在 skb 都还没创建的时候,就把事情处理掉?


4. XDP 是什么

XDP 全称:

text 复制代码
eXpress Data Path

它是 Linux 内核里面一个非常靠前的数据包处理机制。

可以把普通接收路径理解成:

text 复制代码
NIC
 |
Driver
 |
XDP
 |
skb allocation
 |
TC ingress
 |
Network Stack
 |
Socket
 |
Application

XDP 最大的特点就是:

执行位置非常早。

网卡收到数据包以后,在进入完整 Linux 网络协议栈之前,就可以执行 XDP 程序。

所以如果有一个恶意包:

text 复制代码
NIC
 |
XDP
 |
DROP

它甚至不需要进入后面的 Linux 网络协议栈。

也不需要:

text 复制代码
构造 skb
路由查找
iptables
TCP / UDP
Socket

所以 XDP 特别适合处理:

text 复制代码
DDoS 防护
包过滤
高性能转发
负载均衡
流量统计
网络安全

5. 一个 XDP 程序能干什么

XDP 程序执行以后,通常会返回几个典型 Action。

例如:

text 复制代码
XDP_PASS
XDP_DROP
XDP_TX
XDP_REDIRECT

XDP_PASS

表示:

text 复制代码
这个包没问题
继续交给 Linux 网络协议栈

路径变成:

text 复制代码
NIC
 |
XDP
 |
PASS
 |
Linux Network Stack
 |
Application

XDP_DROP

直接丢包:

text 复制代码
NIC
 |
XDP
 |
DROP

后面的协议栈完全不用处理。

这也是 XDP 做 DDoS 防护效率比较高的原因。

XDP_TX

表示:

text 复制代码
从当前网卡直接把包发回去

例如某些简单的响应或者转发场景。

XDP_REDIRECT

表示:

text 复制代码
把数据包重定向到其他地方

例如:

text 复制代码
另一张网卡
另一个 CPU
AF_XDP Socket

这在负载均衡、软路由等场景里面很常见。


6. 为什么 XDP 会比 TC 更快

这里不要简单理解成:

text 复制代码
XDP 一定比 TC 好

更加准确的说法应该是:

XDP 的执行位置更靠前,因此在一些场景下开销更低。

路径可以对比一下。

TC:

text 复制代码
NIC
 |
Driver
 |
skb allocation
 |
TC
 |
Network Stack

XDP:

text 复制代码
NIC
 |
Driver
 |
XDP

如果 XDP 在这里直接:

text 复制代码
DROP

那么后面的:

text 复制代码
skb allocation
Network Stack
Socket

全部不用执行。

所以对于:

text 复制代码
大量需要丢弃的数据包

XDP 优势就会非常明显。

例如 DDoS 攻击。

假设每秒进来几百万个垃圾包。

如果全部进入完整 Linux 协议栈:

text 复制代码
CPU
Memory
skb
协议栈

都会产生压力。

而 XDP 可以直接:

text 复制代码
收到包
↓
判断
↓
DROP

所以成本低很多。


7. 那为什么还需要 TC

既然 XDP 更早、更快,那为什么不全部使用 XDP?

因为越早处理,能拿到的信息通常也越少。

XDP 执行时,数据包还没有走完整个 Linux 网络协议栈。

所以它更适合处理:

text 复制代码
Ethernet
IP
TCP / UDP Header
简单状态
高速过滤
高速转发

如果需要:

text 复制代码
更复杂的网络协议栈信息
skb metadata
Linux Routing 信息
更成熟的流量控制
egress 处理

TC 往往更合适。

尤其是一个非常明显的区别:

XDP 主要关注:

text 复制代码
Ingress

也就是包刚进入机器的时候。

而 TC 可以处理:

text 复制代码
Ingress
+
Egress

所以像:

text 复制代码
出口流量限速
QoS
Traffic Shaping

这类场景,TC 更自然。

因此:

text 复制代码
XDP 和 TC 不是谁取代谁

而是:

text 复制代码
处理位置不同
适合的问题不同

8. DPDK 又是什么

DPDK 全称:

text 复制代码
Data Plane Development Kit

它的思路和 TC、XDP 又不太一样。

前面讲的 TC 和 XDP:

text 复制代码
都还运行在 Linux Kernel 体系里面

只是挂载位置不同。

DPDK 则更加激进。

它的核心思想是:

我直接不走 Linux 网络协议栈了。

普通 Linux:

text 复制代码
NIC
 |
Kernel Driver
 |
Linux Network Stack
 |
Socket
 |
Application

DPDK:

text 复制代码
NIC
 |
DPDK Driver
 |
Userspace Application

中间的:

text 复制代码
Linux Network Stack
Socket

基本被绕过去了。

这种模式通常被称为:

text 复制代码
Kernel Bypass

也就是绕过内核。


9. 为什么绕开内核会更快

Linux 网络协议栈本身其实已经非常成熟。

问题不是 Linux "慢"。

而是:

Linux 必须支持非常通用的场景。

例如:

text 复制代码
TCP
UDP
IPv4
IPv6
iptables
netfilter
namespace
routing
socket
拥塞控制
各种设备
各种协议

为了做到通用,就必然需要很多:

text 复制代码
抽象
数据结构
检查
调度
锁
内存管理

DPDK 面向的是:

text 复制代码
我知道自己要干什么
我只追求高吞吐

所以它可以砍掉很多通用逻辑。

例如一个软路由程序只需要:

text 复制代码
收包
↓
查路由表
↓
改 MAC
↓
发包

那就没必要让数据包经历完整的 Linux TCP/IP 网络协议栈。


10. DPDK 的 Poll Mode

DPDK 里面一个非常关键的设计叫:

text 复制代码
Poll Mode Driver

普通网卡收包经常依赖:

text 复制代码
Interrupt

大致就是:

text 复制代码
网卡收到包
↓
触发中断
↓
CPU 处理中断
↓
处理数据包

如果数据包很少,这种方式非常合理。

因为 CPU 不需要一直盯着网卡。

但在高流量情况下:

text 复制代码
packet
packet
packet
packet
packet
...

大量中断本身也会产生很高的开销。

DPDK 干脆换了一个思路:

text 复制代码
CPU 不睡觉

while (true) {
    看网卡有没有包
    有就处理
}

这就是 Polling。

也就是轮询。

可以简单理解成:

cpp 复制代码
while (true)
{
    recv_packets();
    process_packets();
    send_packets();
}

这样就避免了频繁中断和调度。

代价也很明显:

CPU Core 基本会被占满。

即使暂时没有数据包,它还是在轮询。

所以 DPDK 的使用场景通常不是普通业务 Server。

而是:

text 复制代码
软路由
防火墙
虚拟交换机
电信网络
NFV
高性能负载均衡

这些场景本身就愿意:

text 复制代码
拿几个 CPU Core
专门处理网络

11. DPDK 为什么经常绑核

DPDK 项目里面经常会看到:

text 复制代码
CPU Pinning
Core Binding
NUMA Awareness
HugePage

这些技术其实都是围绕同一个目标:

尽量减少不确定性。

例如一个处理线程:

text 复制代码
Thread
 |
CPU 2

如果 Linux 不断把它调度:

text 复制代码
CPU 2
↓
CPU 15
↓
CPU 7

就容易产生:

text 复制代码
Cache Miss
调度开销
NUMA Remote Access

所以 DPDK 通常会直接:

text 复制代码
一个线程
固定一个 Core

类似:

text 复制代码
RX Queue 0 -> Core 0

RX Queue 1 -> Core 1

RX Queue 2 -> Core 2

每个 Core 专门处理自己的队列。

这样整个数据路径就更加稳定。


12. DPDK 和 NUMA 的关系

DPDK 里面 NUMA 也非常重要。

假设:

text 复制代码
NIC 在 NUMA Node 0

处理 NIC 的线程也在:

text 复制代码
CPU Node 0

Buffer 也分配在:

text 复制代码
Memory Node 0

那么路径就是:

text 复制代码
NIC
 |
Node 0 CPU
 |
Node 0 Memory

基本都是 Local Access。

但如果:

text 复制代码
NIC -> Node 0

CPU -> Node 1

Memory -> Node 1

大量数据就要跨 NUMA Node。

于是会经过 CPU Interconnect:

text 复制代码
Node 0
 |
Interconnect
 |
Node 1

对于 DPDK 这种每秒处理几百万、几千万包的程序来说,这种 Remote Memory Access 会被不断放大。

所以 DPDK 经常会同时考虑:

text 复制代码
NIC NUMA Affinity

CPU Pinning

Memory Placement

也就是:

网卡、CPU 和内存尽量放在同一个 NUMA Node。


13. HugePage 又是为什么

DPDK 里面还经常看到 HugePage。

普通 Linux Page 一般是:

text 复制代码
4 KB

如果应用需要管理非常大的内存,例如:

text 复制代码
10 GB

需要维护非常多 Page。

这会增加:

text 复制代码
Page Table
TLB
地址转换

方面的压力。

所以 DPDK 经常使用:

text 复制代码
2 MB HugePage

甚至

1 GB HugePage

减少 Page 数量。

例如:

text 复制代码
1 GB Memory

如果使用 4 KB Page:

text 复制代码
262144 个 Page

如果使用 2 MB HugePage:

text 复制代码
512 个 Page

数量差别非常大。

因此:

text 复制代码
HugePage
CPU Pinning
NUMA
Polling
Batch Processing

这些技术经常同时出现在 DPDK 里面。


14. DPDK、XDP 和 TC 放在一起看

现在重新把三者放在整个 Linux 网络路径上。

可以粗略画成:

text 复制代码
                    普通 Linux

NIC
 |
Driver
 |
XDP
 |
skb
 |
TC ingress
 |
Linux Network Stack
 |
Socket
 |
Application
 |
TC egress
 |
Driver
 |
NIC

而 DPDK 则是另一条路:

text 复制代码
NIC
 |
DPDK PMD
 |
Userspace Application

所以三者最大的差别可以理解成:

text 复制代码
TC

还在 Linux 网络协议栈中
位置相对靠后
功能丰富


XDP

还在 Linux 内核中
但是位置非常靠前
适合高速过滤和转发


DPDK

直接绕过 Linux 网络协议栈
用户态直接收发包
追求极致性能

15. 三者性能为什么不同

这里可以从"数据包走了多少路"来理解。

TC

大概是:

text 复制代码
NIC
↓
Driver
↓
skb
↓
TC
↓
Network Stack

路径相对完整。

XDP

大概是:

text 复制代码
NIC
↓
Driver
↓
XDP

如果直接 DROP 或 REDIRECT,就可以提前结束。

DPDK

大概是:

text 复制代码
NIC
↓
Userspace

直接绕过内核协议栈。

因此从理论上的极致性能来看,一般会认为:

text 复制代码
DPDK
   >
XDP
   >
传统 Kernel Network Path

但这里不能简单理解成:

text 复制代码
性能越高
技术就越好

因为它们的成本完全不一样。


16. DPDK 的代价

DPDK 性能非常高,但复杂度也很高。

使用 DPDK 以后,Linux 原来的很多能力不能直接使用。

例如:

text 复制代码
Socket
iptables
内核 TCP/IP Stack
很多 Linux 网络工具

你需要自己处理更多东西。

如果程序只是:

text 复制代码
HTTP Server
RPC Server
普通 TCP Server

为了追求一点性能就直接上 DPDK,通常没有太大必要。

因为开发成本和维护成本会明显增加。

所以 DPDK 更适合:

text 复制代码
网络本身就是核心业务

的场景。


17. XDP 的一个优势:还能继续使用 Linux

XDP 相比 DPDK,一个很大的优势就是:

它没有完全绕开 Linux。

例如:

text 复制代码
NIC
 |
XDP
 |
判断是否需要快速处理

如果是普通流量:

text 复制代码
XDP_PASS

继续交给:

text 复制代码
Linux TCP/IP Stack

如果是特殊流量:

text 复制代码
XDP_REDIRECT

走高速路径。

这样可以同时保留:

text 复制代码
Linux 网络协议栈的通用性
+
XDP 的高速处理能力

因此很多现代网络系统会采用:

text 复制代码
Fast Path
+
Slow Path

这种设计。

Fast Path:

text 复制代码
XDP / eBPF

Slow Path:

text 复制代码
Linux Network Stack

简单的、高频的数据包走 Fast Path。

复杂的数据包继续交给 Linux 处理。


18. AF_XDP

XDP 和 DPDK 之间还有一个比较有意思的技术:

text 复制代码
AF_XDP

AF_XDP 可以让 XDP 把数据包直接送到用户态。

路径大概是:

text 复制代码
NIC
 |
XDP
 |
AF_XDP
 |
Userspace

相比普通 Socket:

text 复制代码
NIC
 |
Kernel Network Stack
 |
Socket
 |
Userspace

路径会短很多。

所以 AF_XDP 可以理解成:

Linux 提供的一种高性能用户态收发包机制。

它在某些场景下可以作为:

text 复制代码
普通 Socket
和
DPDK

之间的一个选择。

既希望获得比较高的 Packet Processing 性能,又不想完全进入 DPDK 那套独立生态,就可以考虑 AF_XDP。


19. TC、XDP 和 DPDK 应该怎么选

如果只是普通业务服务:

text 复制代码
HTTP
RPC
TCP Server

一般直接使用:

text 复制代码
Linux Socket

就够了。

如果需要:

text 复制代码
流量控制
QoS
出口限速
网络监控

可以考虑:

text 复制代码
TC / TC eBPF

如果需要:

text 复制代码
DDoS 防护
高性能包过滤
负载均衡
高速转发

可以考虑:

text 复制代码
XDP

如果是:

text 复制代码
软路由
电信数据面
高性能交换
NFV
极致 Packet Processing

可以考虑:

text 复制代码
DPDK

并不是所有项目都应该:

text 复制代码
DPDK > XDP > TC

更加准确的理解应该是:

text 复制代码
普通 Socket
    |
功能最完整
使用最简单


TC
    |
深入 Linux 网络栈处理


XDP
    |
更靠近 Driver
更快处理 Packet


DPDK
    |
直接接管数据平面
性能最高
复杂度也最高

20. 总结

把 DPDK、TC 和 XDP 放到一条网络路径里面,其实就比较容易理解了。

普通 Linux:

text 复制代码
NIC
 |
Driver
 |
XDP
 |
skb
 |
TC
 |
TCP/IP Stack
 |
Socket
 |
Application

DPDK:

text 复制代码
NIC
 |
Userspace Application

因此:

text 复制代码
TC

主要是在 Linux 网络协议栈中对流量进行控制和处理。

text 复制代码
XDP

是在数据包刚进入 Driver 附近时进行非常早期的处理,尽量避免不必要的协议栈开销。

text 复制代码
DPDK

则进一步绕开 Linux 内核网络协议栈,让用户态程序直接处理数据包。

三者背后的核心思想其实都一样:

让数据包尽可能少走没有必要的路径。

只不过它们选择的位置不同。

TC 选择:

text 复制代码
继续使用 Linux 网络协议栈
在协议栈里面做处理

XDP 选择:

text 复制代码
在进入完整协议栈之前
先做一次快速决策

DPDK 选择:

text 复制代码
干脆绕过协议栈
用户态直接处理 Packet

理解了这一点,再去看:

text 复制代码
eBPF
AF_XDP
Kernel Bypass
Zero Copy
RSS
RPS
CPU Pinning
NUMA
HugePage

这些高性能网络相关技术时,就不会再觉得它们是一些互相独立的概念。

它们本质上都在解决一个问题:

怎样让 Packet Processing 更快、更稳定,同时减少 CPU、Memory 和 Kernel Path 上不必要的开销。

相关推荐
徐同保2 小时前
免费ssl证书全流程AI配置(含七牛云cdn)
网络·网络协议·ssl
lisw052 小时前
制造业信息化:现代工业的发展趋势!
大数据·网络·人工智能
陈让然2 小时前
WSL 桥接设置静态IP(快速)
linux·网络·ubuntu
持敬chijing2 小时前
白盒测试与代码审计-js登录逆向实战
javascript·网络·安全·web安全·网络安全·网络攻击模型
乔旭伟3 小时前
Linux 服务器备份实战:一致性快照、日志归档与恢复演练
linux·运维·服务器
乔旭伟3 小时前
Linux 服务器安全加固实战:SSH、防火墙、补丁与入侵排查
linux·服务器·安全
裕晟资质规划4 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全
刘胡子大叔4 小时前
备份包只有 1.5K?
linux·服务器·网络
无足鸟ICT4 小时前
【RHCA+】RPM包验证和数字证书
linux·运维·服务器