20、系统性能优化:低延迟编程技巧
做订单流交易系统,说白了就是跟时间赛跑。别人快你1毫秒,可能就抢走了你碗里的肉。我这些年踩过的坑不少,今天把压箱底的经验掏出来聊聊。
20.1 低延迟编程:三种语言的选择
先说说语言选择。我个人习惯是:核心交易引擎用C++,辅助服务用Java,监控和脚本用Go。为什么这么分?
C++:极致性能的担当
C++是低延迟的王者。我曾在项目中用C++重写过一个Java的订单路由模块,延迟直接从50微秒降到了5微秒。关键技巧就几个:
- 避免虚函数:虚函数调用会打断CPU流水线。我习惯用模板或if-constexpr替代
- 内存池分配:new/delete太慢了,预分配一大块内存自己管理
- 禁用异常:异常处理会生成大量隐藏代码,我一般用返回码
// 一个简单的内存池示例
template<typename T>
class ObjectPool {
char* buffer;
size_t index;
public:
T* allocate() {
return reinterpret_cast<T*>(buffer + (index++ * sizeof(T)));
}
};
Java:GC是最大的敌人
Java做交易系统?可以,但得小心GC。我记得有一次线上系统突然卡顿,一查是Full GC停了200毫秒——这在交易里就是灾难。
- 用堆外内存:DirectByteBuffer绕过GC
- 对象池化:复用对象,减少垃圾产生
- 使用Disruptor:无锁队列,比BlockingQueue快10倍
Go:并发简单但延迟不稳定
Go的goroutine很轻量,但调度器会带来不确定性。我一般用它做日志收集、监控告警这类非核心路径。注意:别在交易核心用Go,GC暂停虽然短,但不可预测。
20.2 内存管理:别让内存成为瓶颈
内存访问延迟是CPU的几十倍。你想想看,一次L1缓存命中只要1纳秒,主存访问要100纳秒。优化内存就是优化性能。
缓存行对齐
CPU缓存是以64字节为单位的缓存行。如果两个线程修改同一个缓存行的不同变量,就会产生伪共享。我曾经因为这个,多线程性能反而比单线程还差。
// 避免伪共享:填充到64字节
struct alignas(64) PaddedCounter {
volatile long value;
char padding[64 - sizeof(long)];
};
数据局部性
遍历数组比遍历链表快得多,因为数组在内存里是连续的。我习惯把热点数据放在连续内存里,用数组而不是vector(vector可能重新分配)。
20.3 缓存优化:把热数据留在CPU里
CPU缓存分L1/L2/L3,容量越来越小但速度越来越快。优化目标就是:让热数据尽量留在L1缓存里。
| 缓存级别 | 典型大小 | 访问延迟 |
|---|---|---|
| L1 | 32KB | ~1ns |
| L2 | 256KB | ~4ns |
| L3 | 8-16MB | ~15ns |
| 主存 | GB级 | ~100ns |
怎么做?减少数据大小。比如订单ID用int64_t而不是string,价格用定点数而不是double。我见过有人用string存股票代码,每次比较都要遍历字符串——改成uint64_t后,速度翻倍。
20.4 并行计算:多核的正确打开方式
现代CPU有几十个核,但并行不是简单开线程。我总结了几条原则:
- 无锁数据结构:锁会阻塞线程,用CAS原子操作替代
- 线程绑定CPU:避免线程在不同核间迁移,用pthread_setaffinity_np
- 分而治之:把订单簿按股票代码分片,每个核处理一片
// 线程绑定到指定CPU核心
void bind_to_core(int core_id) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
}
20.5 FPGA加速:硬件级的极致优化
FPGA是低延迟的终极武器。它用硬件逻辑直接处理数据,没有操作系统、没有中断、没有缓存缺失。延迟可以做到纳秒级。
我参与过一个项目,用FPGA做行情解析和订单检查。结果:
- 行情解析延迟从5微秒降到200纳秒
- 订单风控检查从10微秒降到500纳秒
- 整体吞吐量提升20倍
但FPGA也有代价:开发周期长、调试困难、成本高。我建议:先用软件验证逻辑,再迁移到FPGA。而且不是所有逻辑都适合FPGA——复杂的业务规则还是用CPU处理更灵活。
20.6 知识体系总览
下面这张图是我自己画的,把本章的核心知识点串起来了。你可以把它当作优化路线图:
嗯,这张图基本把本章内容都涵盖了。从软件层的编程语言选择,到内存和缓存优化,再到并行计算和硬件加速,每个环节都有优化空间。但记住:不要一开始就上FPGA,先把软件层面的优化做到极致,再考虑硬件方案。
无相订单流研究社 微信Lucian808555