第三章:做市系统架构

做市系统的架构设计,说白了就是一场与时间的赛跑。我做了这么多年量化,最深的体会就是:延迟每多一微秒,利润就少一分。今天咱们聊聊低延迟系统设计的那些核心原则。

低延迟系统设计原则

我个人习惯把低延迟设计拆成三个层面:硬件、软件、网络。缺一个都不行。

核心原则:减少一切不必要的操作。你想想看,从行情到达到你发出订单,中间每一步都是延迟的累积。

  • 硬件层面:用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;
    }
}

灾备与高可用设计

做市系统最怕什么?怕宕机。一宕机,订单没撤掉,或者报价停了,那损失可不是小数目。所以,高可用是必须的。

我常用的架构是主备模式:

  • 主节点:处理所有交易逻辑,实时同步状态到备节点。
  • 备节点:冷备或温备,主节点挂了立即切换。
  • 仲裁节点:监控主备状态,决定切换时机。

经验之谈:我曾经遇到过主备切换时数据不一致的问题。后来加了状态机,每次切换前先校验数据完整性,才彻底解决。

高可用的几个关键点:

  1. 无单点故障:每个组件都有冗余。
  2. 快速故障检测:心跳超时不能超过100毫秒。
  3. 自动切换:人工切换太慢,必须自动化。
  4. 数据一致性:切换后不能丢订单,不能重复报价。

警告:别以为有了灾备就万事大吉。我曾经见过一个团队,灾备系统从来没演练过,结果真出问题时切换失败,损失惨重。定期演练,必须的。

架构总览

说了这么多,咱们用一张图来总结一下做市系统的核心架构:

做市系统核心架构图 行情接入层 FPGA解析 | 多路行情合并 | 去重与对齐 延迟目标:< 1微秒 事件驱动引擎 无锁队列 | 事件分发 | 异步处理 核心:RingBuffer + 多消费者 策略计算层 报价生成 | 风险管理 | 仓位管理 内存数据库:订单簿、持仓、波动率 订单执行层 FIX协议 | 订单路由 | 成交回报 数据层 Redis Aerospike 本地缓存 日志存储 灾备:主备切换 | 数据同步 | 心跳检测 | 自动恢复

这张图展示了我个人比较推崇的分层架构。每一层各司其职,层与层之间通过事件驱动连接。说白了,就是让数据像流水一样,从行情到策略再到订单,一路畅通无阻。

总结一下:做市系统的架构设计,核心就是低延迟、高可用、事件驱动。这三个点抓住了,系统就稳了。剩下的,就是不断优化、不断测试。

专注资料整理