4、网络协议栈优化:TCP vs UDP vs RDMA、内核旁路技术、零拷贝、网卡多队列与RSS
做市系统里,网络延迟就是真金白银。我见过太多团队,算法写得再漂亮,结果被网络协议栈拖了后腿。今天咱们就聊聊,怎么把这层“中间商”给优化掉。
4.1 TCP vs UDP vs RDMA:选对协议,少走弯路
先说TCP。它可靠、有序,但代价太大。三次握手、拥塞控制、ACK确认——每一个环节都在增加延迟。我在早期做做市系统时,就吃过TCP的亏。行情数据一爆发,TCP的拥塞窗口直接缩成蜗牛,订单根本送不出去。
UDP呢?无连接、无确认、无重传。说白了就是“发了就不管”。但做市场景下,行情数据丢几个包问题不大,订单却不能丢。所以UDP适合行情,不适合交易。
RDMA就厉害了。它允许一台机器的内存直接读写另一台机器的内存,完全绕过操作系统。延迟能压到1微秒以内。我曾在项目中用InfiniBand配合RDMA,把订单处理延迟从20微秒砍到3微秒。嗯,这个数字我记得很清楚。
| 协议 | 延迟(典型值) | 适用场景 | 缺点 |
|---|---|---|---|
| TCP | 10-50 μs | 订单、风控 | 拥塞控制、上下文切换 |
| UDP | 1-5 μs | 行情、心跳 | 不可靠、需应用层处理 |
| RDMA | 1-3 μs | 极速交易、内存共享 | 硬件成本高、配置复杂 |
我的建议:行情走UDP,订单走TCP,如果预算够且延迟敏感,订单链路直接上RDMA。别混用,否则调试起来你会想哭。
4.2 内核旁路技术:绕过操作系统这个“中间商”
为什么内核旁路这么重要?因为每次网络数据进来,都要经过内核协议栈——中断、拷贝、上下文切换。这一套下来,几十微秒就没了。做市系统里,这几十微秒可能就是一笔交易的盈亏。
DPDK(Data Plane Development Kit)是绕开内核的典型方案。它让用户态程序直接接管网卡,轮询收包,零中断。我在搭建行情网关时,用DPDK把收包延迟从30微秒降到了5微秒以内。代价是CPU占用高,但值。
OpenOnload是Solarflare网卡的技术,本质也是内核旁路。它更“聪明”——只加速TCP连接,不改变你的代码。我有个朋友,把交易系统从普通网卡换成Solarflare + OpenOnload,延迟直接砍半。他跟我说:“早知道这么简单,我早换了。”
避坑指南:我曾经在DPDK上踩过一个坑——忘了绑定CPU核心。结果DPDK线程和业务线程抢CPU,延迟反而更高。记住:DPDK线程必须独占核心,不能共享。
4.3 零拷贝技术:数据不动,指针动
传统网络收包,数据要从网卡→内核缓冲区→用户缓冲区,至少拷贝两次。零拷贝就是让数据只在内核和用户态之间共享内存,不搬数据。
实现方式有两种:
- mmap + sendfile:适合文件传输,做市系统用得少。
- DPDK的零拷贝:网卡直接把数据写入用户态内存池,应用直接读。这才是做市场景的王道。
我记得有一次优化订单处理链路,发现数据从网卡到应用走了4次拷贝。改成DPDK零拷贝后,延迟从18微秒降到了7微秒。你想想看,这还没改算法呢,只是把“搬砖”的活省了。
// 传统方式:两次拷贝
recv(sock, buf, len, 0); // 内核→用户
// DPDK零拷贝:直接读内存池
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mempool);
// 数据已经在mbuf里,直接处理
process_packet(mbuf->data, mbuf->data_len);
注意:零拷贝不是银弹。如果数据需要频繁修改或重组,零拷贝反而增加复杂度。我的原则是:只对“读一次就丢”的数据用零拷贝,比如行情快照。
4.4 网卡多队列与RSS:让每个核心都有活干
单队列网卡有个问题:所有数据包都挤在一个队列里,一个CPU核心处理。多核CPU?浪费了。RSS(Receive Side Scaling)就是解决这个的——它根据数据包的哈希值,把不同流分配到不同队列,每个队列绑定一个CPU核心。
做市系统里,RSS特别适合行情数据。比如把不同合约的行情哈希到不同核心,每个核心独立处理。我曾在项目中用4队列网卡,把行情处理吞吐量从50万包/秒提升到200万包/秒。嗯,这个提升很直观。
配置RSS时要注意哈希算法。默认是IP+端口哈希,但做市场景下,同一个IP的不同合约可能哈希到同一个队列。我建议用自定义哈希,把合约ID也加进去。
我的经验:网卡队列数最好等于CPU物理核心数(不是超线程)。比如16核CPU,配16个队列。多了反而因为缓存竞争导致性能下降。
4.5 知识体系总览
下面这张图,是我自己梳理的优化路径。从协议选择到硬件配置,每一步都能压出几微秒。你跟着走一遍,网络延迟至少降一半。
这张图从左到右,从上到下,就是一条完整的优化链路。我个人习惯是:先选协议,再搞内核旁路,然后上零拷贝,最后调多队列。每一步都能看到延迟下降,很有成就感。
最后说一句:网络优化没有银弹。别一上来就上RDMA,先看看你的瓶颈在哪。我曾经见过一个团队,花大价钱上了RDMA,结果发现瓶颈在数据库。嗯,方向错了,再好的技术也白搭。