第二章:高频交易技术栈——低延迟网络、FPGA加速、硬件协同处理、内存数据库

各位同学,欢迎来到第二章。这一章我们聊点硬核的——高频交易的技术栈。

说实话,很多人一听到高频交易,第一反应就是“快”。但快不是目的,比别人快才是目的。我见过太多团队,花大价钱买了最好的硬件,结果架构设计不合理,延迟反而比隔壁用二手服务器的还高。嗯,这里要敲黑板了。

高频交易的技术栈,说白了就是四个核心模块:低延迟网络、FPGA加速、硬件协同处理、内存数据库。咱们一个一个拆开讲。

2.1 低延迟网络:从网卡到交换机,每一纳秒都要抠

先问大家一个问题:你觉得高频交易里,网络延迟的瓶颈在哪?

很多人会说是光纤传输。没错,光速在光纤里大约是2/3c,也就是每公里5微秒左右。但真正让延迟失控的,往往是网络协议栈和硬件处理。

我在项目中遇到过一件事:某次做延迟优化,发现从网卡收到数据包到应用层拿到数据,竟然花了将近10微秒。10微秒啊!这在高频交易里够别人完成好几轮交易了。

怎么解决?核心思路就三个字:去内核

关键知识点:用户态网络栈

传统网络走的是内核协议栈,数据要经过中断处理、协议解析、内存拷贝,延迟高得吓人。高频交易里,我们直接用用户态网络栈,比如Solarflare的OpenOnload、Mellanox的VMA,或者自己写DPDK程序。

举个例子,用DPDK收包,代码大概长这样:

// DPDK 收包核心代码片段
struct rte_mbuf *bufs[BURST_SIZE];
uint16_t nb_rx = rte_eth_rx_burst(port_id, queue_id, bufs, BURST_SIZE);

for (int i = 0; i < nb_rx; i++) {
    // 直接操作mbuf,零拷贝
    process_packet(bufs[i]);
    rte_pktmbuf_free(bufs[i]);
}

你看,没有系统调用,没有中断上下文切换,数据直接从网卡DMA到用户态内存。延迟能从10微秒降到1微秒以内。

我的经验:别迷信“买最贵的网卡”。我见过有人花10万买网卡,结果驱动没调好,延迟比普通网卡还高。DPDK的CPU亲和性、内存大页、NUMA绑定,这些细节才是关键。

2.2 FPGA加速:把逻辑烧进硬件里

接下来聊FPGA。这东西在高频交易圈子里,几乎成了标配。

为什么?因为CPU是通用处理器,它要处理各种指令,有流水线、分支预测、缓存缺失……这些不确定性对高频交易来说是致命的。FPGA不一样,它是硬件逻辑,没有指令周期,没有上下文切换,延迟是确定的。

我建议你记住这个数字:FPGA处理一个UDP数据包,延迟可以做到100纳秒以内。CPU呢?至少1微秒起步。

FPGA在高频交易里主要干三件事:

  • 协议解析:直接从网卡拿到原始以太网帧,解析UDP、TCP、FIX协议
  • 行情解码:把交易所的二进制行情数据,解码成内部数据结构
  • 订单检查:在硬件层面做风控检查,比如价格范围、订单频率

我曾经参与过一个项目,用FPGA做行情解码。交易所的行情数据是自定义二进制格式,CPU解码要花3微秒。我们用FPGA做,直接流水线处理,延迟降到200纳秒。你想想看,这差距有多大。

避坑指南:FPGA开发不是写软件,是写硬件描述语言。我曾经见过一个团队,用Verilog写了一个行情解码器,结果时序没收敛,跑不到目标频率。最后不得不降频,延迟反而比CPU还高。记住:FPGA开发一定要做静态时序分析,确保每个路径都能满足时序要求。

2.3 硬件协同处理:CPU、FPGA、网卡,谁该干什么?

有了FPGA,是不是CPU就没用了?当然不是。高频交易系统里,CPU、FPGA、网卡各司其职,协同工作。

我习惯把整个数据流分成三个阶段:

阶段 硬件 任务 延迟目标
接收 网卡 + FPGA 物理层接收、协议解析、行情解码 < 500ns
决策 CPU + 内存数据库 策略计算、订单生成、风控检查 < 10μs
发送 FPGA + 网卡 订单编码、协议封装、物理层发送 < 500ns

你看,FPGA负责最前和最后,CPU负责中间的逻辑决策。为什么?因为策略逻辑经常变,FPGA改起来太慢。CPU灵活,可以快速迭代。

这里有个细节:CPU和FPGA之间的通信。我建议用PCIe直接内存访问(DMA),或者共享内存。千万别走网络协议栈,那等于把FPGA的优势全浪费了。

实战经验:我在一个项目里,CPU和FPGA之间用PCIe DMA传输数据,延迟大约1微秒。后来我们优化了DMA描述符的提交方式,从轮询改成中断触发,延迟降到300纳秒。嗯,细节决定成败。

2.4 内存数据库:把数据留在内存里

最后聊内存数据库。高频交易里,数据量不大,但要求极快。你不可能去查MySQL,那延迟是毫秒级的,太慢了。

内存数据库的核心思想就一句话:所有数据都在内存里,持久化是异步的

常用的方案有几种:

  • Redis:单线程模型,延迟稳定,适合做缓存和状态管理
  • Aerospike:闪存优化,延迟低,适合做订单簿快照
  • 自己写:很多量化团队会自己实现一个内存数据库,用哈希表或者红黑树,完全定制化

我个人习惯用Redis,但要注意一点:Redis的持久化(RDB/AOF)在高频场景下可能会卡顿。我曾经遇到过,Redis做BGSAVE时,fork子进程导致主进程短暂停顿,延迟飙升到几十毫秒。那一次,我们的策略直接触发了风控熔断。

我的建议:高频交易里,内存数据库只做状态存储,不做持久化。持久化交给另一台机器,或者用日志文件异步写入。别让磁盘IO拖慢你的交易。

另外,内存数据库的访问延迟,要控制在1微秒以内。怎么做到?

  • 共享内存,不走网络
  • 无锁数据结构,避免锁竞争
  • CPU亲和性,把数据库线程绑定到固定核心

举个例子,用共享内存实现一个简单的键值存储:

// 共享内存键值存储(伪代码)
struct shm_kv_store {
    pthread_spinlock_t lock;
    struct kv_pair entries[MAX_ENTRIES];
};

// 写操作
void shm_put(struct shm_kv_store *store, uint64_t key, uint64_t value) {
    pthread_spin_lock(&store->lock);
    // 哈希查找并写入
    store->entries[hash(key) % MAX_ENTRIES] = (struct kv_pair){key, value};
    pthread_spin_unlock(&store->lock);
}

// 读操作
uint64_t shm_get(struct shm_kv_store *store, uint64_t key) {
    pthread_spin_lock(&store->lock);
    uint64_t val = store->entries[hash(key) % MAX_ENTRIES].value;
    pthread_spin_unlock(&store->lock);
    return val;
}

你看,自旋锁、哈希表、共享内存,延迟能控制在几百纳秒。当然,实际生产环境要考虑哈希冲突、内存对齐、缓存行伪共享等问题,这里就不展开了。

小结

这一章我们聊了高频交易技术栈的四个核心模块。说白了,就是让数据从网卡到策略引擎,再到网卡发出去,整个过程延迟越低越好。

低延迟网络解决的是“数据怎么进来”,FPGA解决的是“谁来做最前端的处理”,硬件协同解决的是“怎么分工”,内存数据库解决的是“数据放哪里”。

下一章,我们会深入讲策略引擎的设计。到时候我会分享一个我踩过的坑——策略引擎里用了全局锁,结果延迟直接爆炸。嗯,到时候细聊。

课后思考:如果你现在要设计一个高频交易系统,你会把FPGA放在网卡前面,还是放在CPU后面?为什么?

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