地址:
北京市朝阳区广顺北大街33号院1号楼1单元6685号
工作时间
周一至周五: 9AM - 7PM
周末: 10AM - 5PM
地址:
北京市朝阳区广顺北大街33号院1号楼1单元6685号
工作时间
周一至周五: 9AM - 7PM
周末: 10AM - 5PM

🚀 “榨干”硬件性能,决胜纳秒之间
高频交易系统对延迟要求极高,CPU 缓存命中率直接影响订单的处理速度。现代处理器采用多级缓存(L1/L2/L3),L1 缓存延迟在几纳秒级,而访问主内存需要上百纳秒;因此,如何最大化数据在 L1、L2、L3 缓存中的命中率,尽量避免跨 NUMA 节点或主内存访问,是 HFT 软件设计的核心。本篇从数据结构设计、预热、内存对齐、预分配等角度分析,提高缓存命中率的最佳实践,并介绍缓存和 NUMA 本地化的观测方法。
当数据按结构体(Array of Struct, AoS)存储时,访问每个字段可能跨越多个缓存行;将数据改为结构体数组(Struct of Arrays, SoA)后,同一字段放在连续内存中,可以让 L1/L2 缓存一次加载更多有用数据。根据【3】实测中,使用 AoS 处理 1,000 万元素需要约 208.5 ms,改用 SoA 仅需 163.3 ms,性能提升约 30 %。在 HFT 订单簿或行情队列中应优先选择 SoA,并保证遍历和聚合操作按顺序进行,避免随机访问。
缓存预热(cache warming)指在进入关键交易路径之前主动读取即将使用的数据,使其留在 L1/L2 缓存中。例如,在撮合前对订单薄、风险参数等进行顺序扫描,或发送“假订单”让系统加载流程。根据测试【1】,冷缓存条件下顺序访问大型数组耗时 267 ms,经过预热后运行时间降至 25 ms,减少了约 90 %。在预热过程中,Linux 的 prefetch 指令和编译器提供的 __builtin_prefetch 可提示 CPU 提前加载数据,减少指令流水线停顿。
多线程同时更新不同变量,如果这些变量落在同一缓存行,任何线程写入都会导致其它核的缓存行无效——这被称为假共享。解决方法是将关键数据结构按照缓存行(通常 64 B)对齐,使各线程更新的数据位于不同的缓存行。例如,使用 posix_memalign 分配数组并在结构体中插入填充字段,使得每个元素独占一行。根据【2】测试,给定数据集10w次循环. 未对齐的程序执行时间为 10.92 s,对齐后仅 0.06 s,提升超过 180倍。HFT 中,对计数器、统计数据等共享变量应加 alignas(64) 或使用数组的倍数填充,彻底消除假共享。
多路处理器系统采用 NUMA 架构,每个 CPU 节点拥有本地内存。远程内存访问需要穿越互联总线,延迟比本地访问高约 50 %。最佳实践包括:
numactl --membind 或 set_mempolicy() 将数据绑定到线程所在的 NUMA 节点,避免远程访问。sched_setaffinity),使其一直访问同一缓存和本地内存,提高 L1/L2 命中率。使用这些策略可显著降低远程访问次数,提升 L3 命中率和内存带宽。在测量时可以通过 numastat 或 numatop 观察远程/本地访问比。
高频交易系统往往需要频繁创建、销毁对象(订单、行情等)。频繁调用 new/delete 会导致堆碎片化和 TLB 缓存错失,并产生系统调用延迟。最佳实践是提前分配内存并复用对象,建立固定大小的对象池。某 HFT 实践报告指出,在系统启动时预分配所有数据结构并在主循环中复用可显著降低抖动。对象池可以结合 std::pmr::monotonic_buffer_resource 或自定义内存池实现。
算法设计应充分利用缓存特性:
inline、constexpr,并在编译器优化时指定 -finline-functions。perf 统计指令缓存 miss 数。在频繁的数学计算中,避免不必要的重计算:
Linux 的 perf 工具可以测量应用运行期间的缓存参考次数(cache‑references)和缓存未命中次数(cache‑misses)。
perf stat -e cache-references,cache-misses,L1-dcache-loads,L1-dcache-load-misses \
-e LLC-loads,LLC-load-misses -- ./your_hft_app
cache-references:所有层级缓存访问次数。cache-misses:因缓存未命中而回退到更高层级的次数。L1-dcache-load-misses、LLC-load-misses:分别测量 L1 数据缓存和最后一级缓存 miss。通过比较 miss/访问比即可估算各层命中率。运行程序的不同版本(例如 AoS vs SoA、预热 vs 冷启动),比较 cache-misses 和平均延迟,即可评估改动效果。perf record/perf report 支持生成热路径函数图,定位缓存瓶颈。
NUMA 本地化率反映进程使用本地内存的程度,常用工具包括:
numastat -p <pid>,可以查看进程在各 NUMA 节点上分配的内存页数量,以及跨节点访问情况。local 列表示本地命中页数,other 列表示远程访问。为评估最佳实践,可以编写专用基准程序:
perf 测试缓存 miss。观察 SoA 是否显著减少 miss 并加快速度。perf 检测 cache-references 变化,配合计时函数统计端到端延迟。cache-misses。利用 perf stat -e cache-misses 查看假共享对缓存 miss 的影响。numactl 控制内存绑定,观察吞吐量和延迟;使用 numatop 记录 RMA/LMA 变化。
高频交易系统需要对 CPU 缓存和内存系统有深入理解。通过选择适合的数据布局(SoA)、预热与预取缓存、对齐内存避免假共享、NUMA 亲和与内存本地化、预分配对象以及算法内联与模板化,可以有效提升 L1/L2/L3 命中率并减少不必要的内存访问。采用 Linux perf 和 numastat/numatop 等工具可以量化优化效果,指导进一步调优。通过系统性实践,HFT 软件可在极短时间内处理并反馈订单,维持市场竞争优势。

