网络协议栈优化:TCP vs UDP vs RDMA、零拷贝技术、内核旁路、多队列网卡
行情数据的传输,说白了就是一场与时间的赛跑。你想想看,交易所那边一笔订单刚撮合完,行情数据还在路上,这边量化策略已经等着要了。网络协议栈的每一微秒延迟,都可能让你错过最佳交易时机。今天我们就来聊聊,怎么把这层网络给「榨干」。
TCP vs UDP vs RDMA:选对协议,事半功倍
我个人习惯,先看场景再选协议。低延迟行情系统里,这三种协议各有各的脾气。
TCP:可靠但慢
TCP 有重传机制、拥塞控制,保证数据不丢不乱序。但代价呢?三次握手、ACK 确认、滑动窗口……这些机制在低延迟场景下就是累赘。我在项目中遇到过,用 TCP 收行情,高峰期延迟抖动能到几百微秒,根本没法用。
UDP:快但不靠谱
UDP 没有握手,没有确认,发出去就不管了。延迟低,但丢包、乱序你得自己处理。行情系统里,UDP 是主流选择。为什么?因为行情数据本身就有时间戳和序列号,丢包了可以请求重传,乱序了可以本地排序。
核心要点:UDP 适合「能容忍少量丢包,但绝不能容忍高延迟」的场景。行情数据就是典型。
RDMA:绕过内核,直通内存
RDMA(Remote Direct Memory Access)允许数据直接从一台机器的内存搬到另一台机器的内存,完全绕过操作系统内核。延迟可以降到 1-2 微秒级别。但 RDMA 需要专用网卡和交换机,成本高,部署复杂。我建议,只有当你对延迟有极致要求(比如纳秒级交易)时,才考虑 RDMA。
| 协议 | 延迟 | 可靠性 | 部署成本 | 适用场景 |
|---|---|---|---|---|
| TCP | 10-100μs | 高 | 低 | 非实时、控制指令 |
| UDP | 1-10μs | 低(需应用层处理) | 低 | 行情分发、实时数据 |
| RDMA | 1-2μs | 高 | 高 | 极低延迟交易、高频 |
零拷贝技术:数据不落地,延迟自然低
传统的数据接收流程:网卡 → 内核缓冲区 → 用户缓冲区。数据在内核和用户态之间拷贝了好几次,每次拷贝都是延迟。零拷贝技术就是要把这些多余的拷贝干掉。
DPDK:数据面开发套件
DPDK 让用户态程序直接接管网卡。数据从网卡 DMA 到用户态内存,内核完全不参与。我在项目中用 DPDK 收行情,延迟从 20 微秒降到了 5 微秒以内。但 DPDK 的代价是:你得自己写网卡驱动、轮询收包,CPU 占用率会飙升。
AF_XDP:内核与用户态的桥梁
AF_XDP 是 Linux 内核提供的一种新套接字类型。它允许用户态程序直接访问内核的 XDP(eXpress Data Path)处理后的数据包,避免了数据拷贝。相比 DPDK,AF_XDP 不需要完全绕过内核,部署更简单。我个人觉得,AF_XDP 是 DPDK 的「轻量版」,适合那些不想折腾 DPDK 但又想降低延迟的场景。
// AF_XDP 收包示例(伪代码)
struct xsk_socket_info *xsk;
xsk = xsk_configure(&umem, &config);
while (1) {
// 直接从用户态内存读取数据
struct xdp_desc *desc = xsk_ring_cons__rx_desc(xsk->rx);
// 处理行情数据...
xsk_ring_cons__release(xsk->rx, 1);
}
内核旁路:让操作系统「让路」
内核旁路的思路很简单:不让内核插手网络数据包的处理。DPDK、AF_XDP 都属于内核旁路技术。但内核旁路不是银弹。你想想看,内核虽然慢,但它提供了完整的协议栈、内存管理、进程调度。绕过了内核,这些功能你都得自己实现。
多队列网卡:RSS 与 RPS
现代网卡支持多个硬件队列。每个队列可以绑定到不同的 CPU 核心,实现并行收包。这就是 RSS(Receive Side Scaling)。RSS 的好处是:多个 CPU 核心同时处理网络数据,不会因为单核瓶颈导致丢包。
RPS(Receive Packet Steering)是软件层面的 RSS。如果网卡不支持硬件多队列,RPS 可以在内核里把数据包分发到不同 CPU。但 RPS 有额外的调度开销,我个人不太推荐在低延迟场景下用。
| 技术 | 实现层面 | 延迟 | CPU 开销 | 推荐场景 |
|---|---|---|---|---|
| RSS | 硬件 | 低 | 低 | 所有低延迟场景 |
| RPS | 软件 | 中 | 中 | 网卡不支持 RSS 时的备选 |
配置建议:RSS 的队列数最好等于 CPU 核心数。我曾经见过有人把队列数设成 8,但 CPU 只有 4 核,结果一半队列闲置,另一半队列过载。嗯,这种低级错误,新手常犯。
知识体系结构图
下面这张图,把本章的核心逻辑串起来了。从协议选择,到零拷贝,再到内核旁路和队列优化,每一步都在降低延迟。
说白了,网络协议栈优化没有银弹。你得根据业务场景、硬件条件、团队能力来权衡。我个人建议:先用 UDP 加 AF_XDP 搞定大部分场景,如果延迟还不够,再上 DPDK 或 RDMA。别一上来就追求极致,容易把自己玩进去。