1. 硬件交易系统概述:从软件到硬件的演进
1.1 为什么我们需要聊这个?
做低延迟交易系统,说白了就是跟时间赛跑。
我入行那会儿,大家还在用软件做订单簿。一台高性能服务器,配上C++写的核心逻辑,跑个微秒级延迟,已经算很牛了。但后来我发现,软件再怎么优化,终究有天花板——操作系统调度、CPU中断、缓存未命中,这些开销你躲不掉。
于是,硬件开始登场。
你想想看,FPGA上跑的逻辑,没有操作系统,没有进程切换,没有缓存污染。数据从网口进来,到处理完发出去,走的是一条纯硬件流水线。这个延迟,是纳秒级的。
嗯,这就是我们做这门课的初衷。
1.2 从软件到硬件的演进
我简单梳理一下这个演进过程,你感受下:
| 阶段 | 实现方式 | 典型延迟 | 我踩过的坑 |
|---|---|---|---|
| 纯软件 | C++ 用户态程序 | 10-50 μs | GC暂停、内核调度抖动 |
| 内核旁路 | DPDK、Solarflare | 1-5 μs | CPU亲和性没配好,反而更慢 |
| FPGA加速 | Verilog/VHDL 硬件流水线 | 100-500 ns | 时序收敛搞了我两周 |
| 全硬件订单簿 | FPGA片上BRAM + 并行比较器 | < 100 ns | BRAM不够用,被迫做分层存储 |
你看,从微秒到纳秒,差了整整两个数量级。在交易领域,这可不是小数目。我曾经帮一个客户做优化,把订单簿从软件搬到FPGA上,延迟从12微秒降到了80纳秒。客户当时就说了句:「你们这玩意儿,值。」
1.3 为什么需要硬件订单簿?
这个问题其实很直接——软件订单簿的瓶颈,你绕不过去。
我举个例子。一个典型的软件订单簿,维护一个价格-数量映射表。来一个订单,你要做这几件事:
- 解析网络包(中断 + 拷贝)
- 查找价格档位(红黑树 / 跳表)
- 更新数量(内存写)
- 生成行情快照(序列化)
- 发送出去(系统调用)
每一步都有开销。尤其是查找和更新,在订单量大的时候,CPU缓存命中率直线下降。我见过一个极端情况——某交易所行情爆发时,软件订单簿的延迟从5微秒直接飙到200微秒。这谁受得了?
硬件订单簿就不一样了。FPGA上,价格档位存在BRAM里,比较器阵列并行工作。来一个订单,所有价格档位同时比较,一个时钟周期就能找到匹配的档位。更新也是纯硬件操作,没有锁,没有竞争。
核心差异一句话:软件是串行查找,硬件是并行比较。并行,就是快。
1.4 低延迟交易的核心挑战
做低延迟系统,说白了就三个字:确定性。
延迟低还不够,你得保证每一次的延迟都低。不能这次80纳秒,下次800纳秒。交易系统最怕的就是抖动。
我总结一下核心挑战:
- 时序收敛:FPGA跑在几百兆赫兹,一个路径没收敛,整个设计就废了。我曾经为了一个跨时钟域的问题,调了整整三天。
- 资源限制:FPGA的BRAM、DSP、LUT都是有限的。订单簿深度越大,资源消耗越大。你得学会做取舍。
- 流水线深度:硬件流水线越长,延迟越大。但流水线太短,又跑不高频率。这是个平衡艺术。
- 数据一致性:多个订单同时到达,你怎么保证状态不乱?硬件里没有锁,全靠设计保证。
注意:千万不要以为FPGA就是「把C代码翻译成Verilog」。我见过太多人这么干,结果跑出来的延迟比软件还差。硬件思维和软件思维,完全是两码事。
1.5 硬件订单簿的整体架构
下面这张图,是我个人习惯用的硬件订单簿顶层架构。你看一眼,心里就有数了:
我的经验:刚开始做硬件订单簿时,我总想把所有功能塞到一个模块里。结果时序一塌糊涂。后来学乖了,把协议解析、订单簿核心、行情生成拆成三个独立流水线,中间用FIFO缓冲。这样每个模块的时序都好收敛,调试也方便。
1.6 一个简单的例子:价格档位查找
我拿价格档位查找举个例子,你就明白硬件和软件的区别了。
软件里,你可能会这么写:
// 软件:红黑树查找
auto it = price_map.find(order_price);
if (it != price_map.end()) {
it->second.quantity += order_qty;
}
这段代码,平均查找复杂度是 O(log n)。n 是价格档位数。如果市场上有1000个价格档位,大约需要10次比较。每次比较还有分支预测、缓存访问的开销。
硬件里,我们这么干:
// 硬件:并行比较器
always @(posedge clk) begin
for (i = 0; i < NUM_LEVELS; i = i + 1) begin
if (price[i] == order_price) begin
quantity[i] <= quantity[i] + order_qty;
end
end
end
注意看,这个 for 循环在硬件里是并行展开的。所有价格档位同时比较,一个时钟周期就出结果。不管你有10个档位还是1000个档位,延迟都一样。
关键点:硬件里,并行是免费的。只要你资源够,想并多少就并多少。这就是硬件订单簿能跑到纳秒级的根本原因。
1.7 避坑指南
最后,分享几个我踩过的坑:
- 别迷信「全硬件」:不是所有逻辑都适合搬到FPGA上。复杂的业务逻辑、频繁变更的规则,还是留给软件处理。硬件只做最核心、最稳定的部分。
- 重视仿真:我吃过一次大亏——仿真跑得好好的,上板就挂。后来发现是复位逻辑没处理好。硬件调试比软件麻烦得多,仿真能帮你省下大量时间。
- 预留调试接口:FPGA内部的状态,你总得有个办法看。我习惯在每个模块都加一个AXI-Lite寄存器接口,方便上位机读取内部状态。
血的教训:我曾经在一个项目里,为了省几个LUT,把调试接口全删了。结果上板后订单簿行为异常,我花了整整一周才定位到问题——一个跨时钟域的同步器少打了一拍。从那以后,我再也不敢省调试接口了。
好了,这一章就聊到这儿。硬件订单簿的世界,才刚刚打开。后面的章节,我们会一步步深入,从协议解析到价格匹配,从行情生成到性能调优。你准备好了吗?
公众号:蓝海资料掘金营,微信deep3321