第四章:网络协议栈:从TCP到UDP,再到RDMA与内核旁路技术
做量化交易的朋友,尤其是搞高频的,一定对网络延迟又爱又恨。我刚开始入行那会儿,总觉得代码写得够快就行了,网络嘛,交给操作系统不就好了?结果被现实狠狠教育了一顿。
今天咱们聊聊网络协议栈。说白了,就是数据从你的交易程序发出去,到交易所服务器收到,中间经历了什么。这条路,走法不同,延迟天差地别。
4.1 TCP:可靠但慢,为什么?
TCP,传输控制协议。它最大的特点就是可靠。你发一个包,对方必须回一个ACK确认。没收到?重传。这保证了数据不丢、不乱序。
但代价呢?延迟。
我举个例子。你在交易系统里发一个订单,TCP会先建立连接——三次握手。你想想看,光是握手就多了一个RTT(往返时间)。在微秒级的世界里,这简直是灾难。
还有更坑的:TCP的拥塞控制。网络稍微有点抖动,它自动降低发送速率。你这边行情正猛,它给你来个慢启动……嗯,我遇到过,那感觉就像赛车手在直道上被踩了刹车。
4.2 UDP:快,但你要自己兜底
UDP就简单粗暴了。它不管对方收没收到,只管发。没有握手,没有拥塞控制,没有重传。延迟极低。
但问题来了:丢包怎么办?
我个人的习惯是:在应用层自己做可靠性。比如,每个UDP包加一个序列号。接收方发现序号跳了,就知道丢了包。至于要不要重传,看业务场景。
对于行情数据,丢了就丢了,下一笔马上来。对于订单,必须保证送达,那就自己实现一个轻量级的确认机制。
4.3 内核旁路:绕过操作系统
不管是TCP还是UDP,数据都要经过操作系统内核。内核负责协议栈处理、数据拷贝、上下文切换。这些操作,每一个都是延迟的元凶。
你想想看,你的交易程序在用户态,网卡在内核态。数据从网卡到应用程序,要经过:
- 网卡收到数据,触发中断
- 内核处理中断,拷贝数据到内核缓冲区
- 内核协议栈处理(TCP/UDP头部解析)
- 内核把数据拷贝到用户态缓冲区
- 系统调用返回,你的程序才能读到数据
这一套下来,几百纳秒到几微秒就没了。对于高频交易,这太奢侈了。
所以有了内核旁路技术。说白了,就是让应用程序直接和网卡对话,跳过内核。
4.4 RDMA:远程直接内存访问
RDMA,Remote Direct Memory Access。它允许一台机器的应用程序直接读写另一台机器的内存,而不需要经过双方的CPU和操作系统。
怎么做到的?
网卡上有个专门的硬件,叫RNIC(RDMA网卡)。它自己处理协议栈,直接和应用程序的内存交互。数据从网卡到应用内存,零拷贝,零内核参与。
我做过一个测试:同样的数据量,TCP延迟大约10微秒,RDMA可以做到1微秒以内。差距是数量级的。
4.5 几种技术的对比
| 技术 | 延迟(典型值) | CPU占用 | 可靠性 | 适用场景 |
|---|---|---|---|---|
| TCP | 10-50 μs | 高 | 高 | 非高频交易、管理通道 |
| UDP | 1-5 μs | 中 | 低(需应用层保证) | 行情数据、低延迟信号 |
| 内核旁路(如DPDK) | 0.5-2 μs | 低 | 中 | 高频交易、极速行情 |
| RDMA | 0.5-1 μs | 极低 | 高(硬件保证) | 极速交易、内存数据同步 |
4.6 知识体系图
下面这张图,展示了从传统TCP到RDMA的演进路径,以及各层级的延迟瓶颈。
4.7 实际选型建议
说了这么多,到底怎么选?我个人的经验是这样的:
- 管理通道、风控、清算:用TCP。稳定第一,延迟无所谓。
- 行情接收:用UDP。丢几个包没关系,下一笔马上来。但要做好应用层的丢包检测和补偿。
- 极速交易:上内核旁路或RDMA。我目前在用的就是DPDK + 用户态协议栈,延迟稳定在1微秒以内。
嗯,网络协议栈这块,说白了就是“用硬件换时间”。你愿意花多少钱买硬件,决定了你能把延迟压到多低。但不管怎么选,理解底层原理,才能做出正确的取舍。