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可靠但慢,UDP快但需要自己兜底,RDMA快得离谱但贵得吓人。怎么选?看你的业务需求。
我个人习惯是:行情用UDP组播+FEC,订单用UDP单播+应用层确认,只有对账等非实时操作才用TCP。至于RDMA,如果你的交易延迟要求低于5微秒,而且预算充足,那就上吧。