4、传输层基石:TCP的拥塞控制对交易的影响、UDP的不可靠性如何被克服、RDMA技术初探

聊到交易所的网络协议栈,传输层是个绕不开的坎儿。很多人觉得TCP可靠、UDP快,选哪个一目了然。但真在交易系统里摸爬滚打过,你会发现事情没那么简单。

我个人习惯把传输层比作交易所的「血管」。TCP像是一条有交警管制的国道,稳当但偶尔堵车;UDP像是一条没有红绿灯的乡间小路,快但容易翻车。而RDMA呢?它更像是给高频交易修了一条专属高铁。

今天我们就来扒一扒这三者的底裤。嗯,先从TCP的拥塞控制说起。

4.1 TCP拥塞控制:交易延迟的隐形杀手

TCP的拥塞控制,说白了就是网络太挤了,TCP自己主动降速。这个机制在下载文件时是好事,但在交易场景下,它就是噩梦。

为什么会这样? 因为TCP的拥塞控制算法(比如CUBIC、BBR)会动态调整发送窗口。一旦检测到丢包,它立马把发送速率砍半。你想想看,一个做市商的订单流正在全速发送,突然因为网络抖动丢了一个包,TCP直接降速——接下来几百微秒的订单可能都发不出去。

核心问题:TCP的拥塞控制是为「公平共享带宽」设计的,不是为「低延迟」设计的。在交易场景下,公平不重要,快才重要。

我在项目中遇到过一件事。某家期货公司的行情网关用的是TCP,结果在开盘瞬间,大量订阅请求涌入,TCP连接开始出现重传。重传导致拥塞窗口缩小,窗口缩小导致更多请求排队,排队导致延迟飙升——典型的拥塞崩溃。后来我们换成UDP+应用层重传,问题才解决。

避坑指南:我曾经建议一个团队,如果非要用TCP做交易通道,一定要禁用Nagle算法(TCP_NODELAY),并且把socket的发送/接收缓冲区调大。但说实话,这只是治标不治本。

TCP特性 对交易的影响 我的建议
慢启动 新建连接初期吞吐量低 长连接复用,避免频繁建连
拥塞避免 丢包后吞吐量腰斩 使用UDP或RDMA替代
快速重传 重传导致延迟抖动 应用层做冗余发送
ACK累积 批量确认增加延迟 关闭延迟ACK(TCP_QUICKACK)

4.2 UDP的不可靠性:如何被克服?

UDP快,但不可靠。丢包了怎么办?乱序了怎么办?这是每个用UDP做交易系统的人都要回答的问题。

说白了,UDP只负责把数据包扔到网络上,至于到没到、顺序对不对,它不管。那交易所怎么用UDP?答案是:在应用层自己搞定可靠性。

常见的做法有三种:

  • 冗余发送:同一个数据包发两遍甚至三遍。丢一个没关系,另一个能到就行。代价是带宽翻倍。
  • 序列号+去重:每个UDP包带一个递增的序列号。接收端根据序列号排序,重复的包直接丢弃。
  • FEC前向纠错:发送一些冗余校验包,接收端即使丢了一两个包,也能通过数学计算恢复出来。

我记得有一次帮一个做市商团队优化行情推送。他们用的是UDP组播,但偶尔会出现几百微秒的丢包。我建议他们加上FEC,丢包率从0.1%降到了0.001%以下。虽然FEC会增加一点CPU开销,但比起TCP的重传延迟,这点代价完全可以接受。

我的经验:UDP的不可靠性不是缺陷,而是特性。你想想看,TCP为了保证可靠,做了多少额外工作?这些工作在交易场景下大部分是浪费的。UDP把控制权交给你,让你自己决定「什么程度的可靠是可接受的」。

但要注意,UDP也有坑。比如UDP的接收缓冲区满了之后,内核会直接丢包,不会通知应用程序。我曾经见过一个系统,接收端处理速度跟不上发送端,结果UDP缓冲区溢出,大量行情数据无声无息地丢了。排查了三天才发现是缓冲区大小没配够。

警告:使用UDP时,一定要监控接收端的丢包率。很多系统上线时跑得好好的,一遇到流量高峰就崩,就是因为UDP缓冲区溢出。

4.3 RDMA技术初探:绕过内核的「高铁」

聊完TCP和UDP,我们来看看RDMA。RDMA的全称是Remote Direct Memory Access,远程直接内存访问。说白了,就是让一台机器的网卡直接读写另一台机器的内存,完全绕过CPU和操作系统内核。

为什么RDMA快? 传统网络通信,数据要从网卡到内核缓冲区,再从内核缓冲区拷贝到用户空间。这一来一回,CPU参与了好几次拷贝,延迟自然高。RDMA呢?网卡直接把数据放到用户空间的内存里,CPU全程不参与。

我刚开始接触RDMA时,觉得这东西太神奇了。后来在实验室里搭了一套InfiniBand环境,测了一下延迟——1微秒以内。而同样的机器用TCP,延迟在10微秒左右。差了整整一个数量级。

RDMA的两种主要实现:

  • InfiniBand:专用硬件,延迟最低,但贵。适合顶级交易所。
  • RoCE(RDMA over Converged Ethernet):跑在普通以太网上,成本低,但需要交换机支持PFC(优先级流控制)。

不过RDMA也不是银弹。它的编程模型和传统socket完全不同。你没法用read/write,得用ibv_post_send、ibv_post_recv这些API。而且RDMA的内存注册、队列对管理,稍有不慎就会导致性能暴跌。

我的建议:如果你的交易系统延迟要求在10微秒以上,用UDP就够了。如果要求在5微秒以下,可以考虑RDMA。但要做好心理准备——RDMA的学习曲线很陡,调试起来也很痛苦。

我记得有一次帮客户调优RDMA性能。他们用的是RoCE v2,但延迟始终降不到1微秒以下。查了半天,发现是交换机的PFC配置有问题,导致偶尔出现流控暂停帧。调整之后,延迟直接降到800纳秒。嗯,硬件层面的坑,有时候比软件还多。

4.4 本章知识体系

为了让你更直观地理解这三者的关系,我画了一张图。这张图展示了从TCP到UDP再到RDMA的演进逻辑,以及各自适用的场景。

传输层协议对比与选型 TCP 可靠但慢 拥塞控制是双刃剑 适合:订单确认 延迟:10-100μs ⚠ 避免用于行情 UDP 快但不可靠 应用层自己搞定可靠性 适合:行情推送 延迟:1-10μs ✓ 主流选择 RDMA 绕过内核,直接内存访问 延迟最低,但成本高 适合:高频交易 延迟:<1μs ★ 终极方案 延迟越低 → 越适合高频交易 选型原则:在满足可靠性的前提下,选择延迟最低的方案

这张图其实想表达一个核心观点:没有完美的传输层协议,只有最适合场景的协议。TCP可靠但慢,UDP快但需要自己兜底,RDMA快得离谱但贵得吓人。怎么选?看你的业务需求。

我个人习惯是:行情用UDP组播+FEC,订单用UDP单播+应用层确认,只有对账等非实时操作才用TCP。至于RDMA,如果你的交易延迟要求低于5微秒,而且预算充足,那就上吧。


专注资料整理