网络协议栈优化:TCP vs UDP vs RDMA、零拷贝技术、内核旁路、多队列网卡

行情数据的传输,说白了就是一场与时间的赛跑。你想想看,交易所那边一笔订单刚撮合完,行情数据还在路上,这边量化策略已经等着要了。网络协议栈的每一微秒延迟,都可能让你错过最佳交易时机。今天我们就来聊聊,怎么把这层网络给「榨干」。

TCP vs UDP vs RDMA:选对协议,事半功倍

我个人习惯,先看场景再选协议。低延迟行情系统里,这三种协议各有各的脾气。

TCP:可靠但慢

TCP 有重传机制、拥塞控制,保证数据不丢不乱序。但代价呢?三次握手、ACK 确认、滑动窗口……这些机制在低延迟场景下就是累赘。我在项目中遇到过,用 TCP 收行情,高峰期延迟抖动能到几百微秒,根本没法用。

避坑指南:我曾经在某个期货行情项目里,试图用 TCP 的 Nagle 算法优化小包延迟,结果反而把延迟搞得更糟。后来直接禁用了 Nagle,才算稳住。

UDP:快但不靠谱

UDP 没有握手,没有确认,发出去就不管了。延迟低,但丢包、乱序你得自己处理。行情系统里,UDP 是主流选择。为什么?因为行情数据本身就有时间戳和序列号,丢包了可以请求重传,乱序了可以本地排序。

核心要点:UDP 适合「能容忍少量丢包,但绝不能容忍高延迟」的场景。行情数据就是典型。

RDMA:绕过内核,直通内存

RDMA(Remote Direct Memory Access)允许数据直接从一台机器的内存搬到另一台机器的内存,完全绕过操作系统内核。延迟可以降到 1-2 微秒级别。但 RDMA 需要专用网卡和交换机,成本高,部署复杂。我建议,只有当你对延迟有极致要求(比如纳秒级交易)时,才考虑 RDMA。

协议延迟可靠性部署成本适用场景
TCP10-100μs非实时、控制指令
UDP1-10μs低(需应用层处理)行情分发、实时数据
RDMA1-2μs极低延迟交易、高频

零拷贝技术:数据不落地,延迟自然低

传统的数据接收流程:网卡 → 内核缓冲区 → 用户缓冲区。数据在内核和用户态之间拷贝了好几次,每次拷贝都是延迟。零拷贝技术就是要把这些多余的拷贝干掉。

DPDK:数据面开发套件

DPDK 让用户态程序直接接管网卡。数据从网卡 DMA 到用户态内存,内核完全不参与。我在项目中用 DPDK 收行情,延迟从 20 微秒降到了 5 微秒以内。但 DPDK 的代价是:你得自己写网卡驱动、轮询收包,CPU 占用率会飙升。

我的经验:DPDK 适合行情网关这类专用节点。如果是一台通用服务器,既要跑行情又要跑策略,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 核,结果一半队列闲置,另一半队列过载。嗯,这种低级错误,新手常犯。

知识体系结构图

下面这张图,把本章的核心逻辑串起来了。从协议选择,到零拷贝,再到内核旁路和队列优化,每一步都在降低延迟。

网络协议栈优化知识体系 协议选择 TCP(可靠但慢) UDP(快但不靠谱) RDMA(极致低延迟) 零拷贝技术 DPDK(用户态接管网卡) AF_XDP(内核桥接) 内核旁路 绕过内核协议栈,直接处理数据包 多队列网卡 RSS(硬件分发) RPS(软件分发)

说白了,网络协议栈优化没有银弹。你得根据业务场景、硬件条件、团队能力来权衡。我个人建议:先用 UDP 加 AF_XDP 搞定大部分场景,如果延迟还不够,再上 DPDK 或 RDMA。别一上来就追求极致,容易把自己玩进去。