第4章:网络协议栈:从TCP到UDP,再到RDMA与用户态协议栈的演进

做高频交易这些年,我最大的感触就是——网络协议栈的选择,直接决定了你的交易延迟是微秒级还是毫秒级。说白了,这就是一场与操作系统内核的博弈。

今天咱们聊聊协议栈的演进之路。这条路我走了十几年,踩过的坑不少,但收获也很大。

4.1 TCP:稳定但慢,为什么?

TCP 是互联网的基石。可靠、有序、流量控制,这些特性让它成为通用场景的首选。

但在高频交易里,TCP 有个致命问题——延迟太高。

为什么会这样?我拆开给你看:

  • 三次握手:每次建立连接都要来回一次,1个RTT就没了
  • 拥塞控制:慢启动、拥塞避免,这些算法在交易网络里完全是累赘
  • ACK确认机制:每个包都要等确认,浪费带宽也浪费时间
  • 内核态开销:每次收发数据都要陷入内核,上下文切换的成本很高

核心问题:TCP 的设计目标是公平和可靠,而不是低延迟。在高频交易这种“确定性优先”的场景里,TCP 的很多机制反而成了负担。

我记得有一次,帮一家做市商优化交易链路。他们用的是标准 TCP,订单从生成到到达交易所,平均延迟是 120 微秒。我们换成 UDP 后,直接降到了 25 微秒。你想想看,这差距有多大。

4.2 UDP:轻量但不可靠,怎么用?

UDP 没有握手、没有拥塞控制、没有重传。它就是个“发出去就不管”的协议。

但正因为简单,它才快。

在高频交易里,UDP 的典型用法是:

  • 行情数据推送:丢几个包没关系,下一笔马上就到
  • 订单发送:在应用层自己做重传和校验
  • 时间同步:PTP 协议就是基于 UDP 的

不过,UDP 也不是银弹。我遇到过一个问题:UDP 没有流量控制,如果发送端太快,接收端的缓冲区会溢出,导致丢包。嗯,这里要注意——在高频场景下,丢包率哪怕只有 0.1%,也可能导致策略失效。

我的建议:用 UDP 时,一定要在应用层实现简单的确认和重传机制。别指望内核帮你擦屁股。

4.3 RDMA:绕过内核,直击硬件

RDMA(Remote Direct Memory Access)是真正的“降维打击”。它允许一台机器的应用直接读写另一台机器的内存,完全绕过操作系统内核。

我最早接触 RDMA 是在 2015 年,当时帮一家量化基金搭建交易系统。他们从纽约到芝加哥的链路,用 TCP 延迟是 7.3 毫秒,换成 RDMA 后降到了 3.8 毫秒。几乎砍了一半。

RDMA 的核心优势:

  • 零拷贝:数据直接从网卡到应用内存,不需要经过内核缓冲区
  • 内核旁路:不需要系统调用,省去了上下文切换
  • CPU卸载:数据传输由网卡硬件完成,CPU 可以专心做计算

RDMA 有两种主流实现:

特性 InfiniBand RoCEv2
延迟 极低(<1μs) 低(1-3μs)
成本 高(专用硬件) 中等(以太网+RDMA网卡)
兼容性 需要专用交换机 兼容标准以太网
部署难度 中等

避坑指南:我曾经在 RoCEv2 上踩过一个坑——PFC(优先级流控)配置不当,导致整个网络出现死锁。后来花了整整两周才定位到问题。所以,用 RDMA 之前,一定要先做充分的网络调优。

4.4 用户态协议栈:终极武器

如果说 RDMA 是绕过内核,那用户态协议栈就是“自己造轮子”。

什么意思?就是把整个 TCP/IP 协议栈搬到用户空间,完全由应用控制。这样做的优势很明显:

  • 零系统调用:所有操作都在用户态完成
  • 自定义协议:可以去掉不需要的头部字段,减少包大小
  • 确定性延迟:没有内核调度干扰,延迟更稳定

常见的用户态协议栈方案:

  • DPDK:Intel 出品,最流行的用户态网络框架
  • Solarflare OpenOnload:专为金融交易设计的协议栈
  • Mellanox VMA:配合 Mellanox 网卡使用,延迟极低

下面是一个简单的 DPDK 接收数据包的示例:

// DPDK 接收数据包示例
static void lcore_recv_packets(void) {
    struct rte_mbuf *bufs[BURST_SIZE];
    uint16_t nb_rx;
    
    while (1) {
        // 从网卡接收一批数据包
        nb_rx = rte_eth_rx_burst(port_id, 0, bufs, BURST_SIZE);
        
        if (unlikely(nb_rx == 0))
            continue;
        
        // 处理每个数据包
        for (int i = 0; i < nb_rx; i++) {
            process_packet(bufs[i]);
            rte_pktmbuf_free(bufs[i]);
        }
    }
}

这段代码看起来简单,但背后涉及的东西很多。比如内存池管理、NUMA 亲和性、CPU 隔离等等。我刚开始用 DPDK 时,光是调优内存分配就花了一周。

关键点:用户态协议栈不是万能的。它需要应用层自己处理 TCP 的可靠性、重传、流量控制等逻辑。开发成本很高,但延迟收益也很可观。

4.5 协议栈选择决策树

说了这么多,到底该怎么选?我画了一张图,帮你理清思路:

协议栈选择决策树 延迟要求 < 10μs? RDMA 或 用户态协议栈 TCP 或 UDP InfiniBand RoCEv2 UDP + 应用层重传 TCP + 内核调优 注:实际选择还需考虑成本、团队能力、现有基础设施等因素 典型延迟参考 TCP(标准内核):50-200μs UDP(优化后):10-50μs RDMA(InfiniBand):<1μs 用户态协议栈(DPDK):1-5μs

4.6 实战经验总结

做了这么多年高频交易网络,我总结了几条经验:

  1. 不要迷信某个协议。TCP 有 TCP 的适用场景,UDP 有 UDP 的局限。关键是看你的业务需求。
  2. 延迟和吞吐量要分开看。高频交易更关注延迟,尤其是尾部延迟(99.9%分位)。
  3. 硬件加速是趋势。不管是 RDMA 还是 DPDK,都在把工作从 CPU 卸载到网卡上。
  4. 测试环境要贴近生产。我见过太多人在实验室里测出 1μs 延迟,上线后变成 10μs。网络抖动、交换机缓存、光纤长度,这些都会影响实际表现。

我的习惯:每次做协议栈选型时,我都会先跑一个简单的 ping-pong 测试,看看基础延迟。然后再加负载,看延迟分布。最后才决定用哪个方案。

好了,这一章就聊到这里。协议栈的选择没有标准答案,但理解了 TCP、UDP、RDMA 和用户态协议栈的优缺点,你就能根据实际情况做出最优决策。


公众号:蓝海资料掘金营,微信deep3321