第三章:做市系统架构
做市系统的架构设计,说白了就是一场与时间的赛跑。我做了这么多年量化,最深的体会就是:延迟每多一微秒,利润就少一分。今天咱们聊聊低延迟系统设计的那些核心原则。
低延迟系统设计原则
我个人习惯把低延迟设计拆成三个层面:硬件、软件、网络。缺一个都不行。
核心原则:减少一切不必要的操作。你想想看,从行情到达到你发出订单,中间每一步都是延迟的累积。
- 硬件层面:用FPGA做行情解析,用固态硬盘,甚至把网卡绑到特定CPU核心上。我在项目中遇到过,光是把网卡中断绑定到独立核心,延迟就降了30%。
- 软件层面:避免锁竞争,用无锁队列,减少系统调用。说白了,能用户态解决的问题就别麻烦内核。
- 网络层面:同机房部署,用低延迟交换机,甚至用光纤直连。我曾经见过一个团队,为了省0.5微秒,把服务器搬到了交易所机房里。
避坑指南:我曾经以为代码优化就够了,结果发现GC暂停才是罪魁祸首。后来改用对象池和栈上分配,才把问题解决。
事件驱动架构
做市系统本质上就是个事件处理机。行情来了、订单成交了、风控触发了——这些都是事件。事件驱动架构,就是把这些事件串起来,让它们有序流动。
我常用的模式是这样的:
// 伪代码示例:事件循环核心
while (running) {
Event event = eventQueue.dequeue(); // 无锁队列取出事件
switch (event.type) {
case TICK:
updatePrice(event.data);
checkQuotes();
break;
case FILL:
updatePosition(event.data);
rebalance();
break;
case RISK_CHECK:
haltTrading();
break;
}
}
这里有个关键点:事件队列必须是无锁的。用锁?那延迟就上去了。我推荐用Disruptor或者自己实现一个RingBuffer。
注意:事件处理不能阻塞。如果某个事件处理时间长了,后面的都得等着。所以我会把耗时操作异步化,或者干脆丢到另一个线程池里。
内存数据库与缓存策略
做市系统里,速度就是生命。用磁盘数据库?那延迟直接爆炸。所以,内存数据库是标配。
我常用的方案:
| 组件 | 用途 | 延迟 |
|---|---|---|
| Redis | 订单簿快照、账户余额 | ~1微秒 |
| Aerospike | 历史行情、策略参数 | ~10微秒 |
| 本地HashMap | 实时订单簿、持仓 | 纳秒级 |
你可能会问:为什么不用纯内存数据结构?嗯,这里有个权衡。纯内存最快,但重启就丢了。Redis虽然慢一点,但能持久化。我个人习惯是:核心数据用本地内存,辅助数据用Redis。
缓存策略:我一般用LRU淘汰旧数据,但做市系统里有个坑——行情数据更新太快,缓存命中率其实不高。所以,我反而会缓存计算结果,比如实时波动率、价差等。
举个例子:
// 缓存实时波动率
public class VolatilityCache {
private ConcurrentHashMap<String, Double> cache = new ConcurrentHashMap<>();
public double getVolatility(String symbol) {
return cache.computeIfAbsent(symbol, this::calculateVolatility);
}
private double calculateVolatility(String symbol) {
// 计算逻辑,这里省略
return 0.15;
}
}
灾备与高可用设计
做市系统最怕什么?怕宕机。一宕机,订单没撤掉,或者报价停了,那损失可不是小数目。所以,高可用是必须的。
我常用的架构是主备模式:
- 主节点:处理所有交易逻辑,实时同步状态到备节点。
- 备节点:冷备或温备,主节点挂了立即切换。
- 仲裁节点:监控主备状态,决定切换时机。
经验之谈:我曾经遇到过主备切换时数据不一致的问题。后来加了状态机,每次切换前先校验数据完整性,才彻底解决。
高可用的几个关键点:
- 无单点故障:每个组件都有冗余。
- 快速故障检测:心跳超时不能超过100毫秒。
- 自动切换:人工切换太慢,必须自动化。
- 数据一致性:切换后不能丢订单,不能重复报价。
警告:别以为有了灾备就万事大吉。我曾经见过一个团队,灾备系统从来没演练过,结果真出问题时切换失败,损失惨重。定期演练,必须的。
架构总览
说了这么多,咱们用一张图来总结一下做市系统的核心架构:
这张图展示了我个人比较推崇的分层架构。每一层各司其职,层与层之间通过事件驱动连接。说白了,就是让数据像流水一样,从行情到策略再到订单,一路畅通无阻。
总结一下:做市系统的架构设计,核心就是低延迟、高可用、事件驱动。这三个点抓住了,系统就稳了。剩下的,就是不断优化、不断测试。