第一章:交易系统架构设计 — C/S vs 微服务,核心组件与延迟分析

大家好,我是你们的讲师。今天咱们聊聊交易系统的骨架——架构设计。

说实话,我见过太多团队一上来就追微服务,结果延迟高得离谱。也见过死守C/S架构的,最后扩展性成了噩梦。嗯,这里头门道不少。

1.1 C/S架构 vs 微服务架构:怎么选?

先问个问题:高频交易最怕什么?延迟。第二怕什么?系统崩了。

C/S架构(客户端-服务器),说白了就是一台机器干所有事。行情来了,策略算,下单走,全在一个进程里。我早期做期货高频时,用的就是这种。好处是啥?延迟极低,内存里直接读写,没有网络开销。坏处呢?耦合太紧,改个风控逻辑得重启整个系统。

微服务架构,就是把行情、策略、交易、风控拆成独立服务。每个服务可以单独部署、单独升级。我在一个做市商项目里见过,他们把策略引擎拆成了十几个微服务,每个管一个品种。好处是灵活,坏处是——延迟!服务间通信走网络,哪怕用Unix Domain Socket,也比进程内调用多几个微秒。

我的建议:

  • 如果你做的是纳秒级高频交易(比如股指期货套利),老老实实用C/S架构。延迟是第一优先级。
  • 如果你做的是毫秒级中高频交易(比如商品期货趋势跟踪),微服务架构更合适。扩展性和维护性更重要。

避坑指南:我曾经在一个项目里强行把行情网关和策略引擎拆成两个微服务,结果行情数据从网卡到策略引擎走了三次进程间通信,延迟从5微秒飙到了50微秒。后来我学乖了——关键路径上的组件,能放一个进程就别拆。

1.2 核心组件拆解

不管选哪种架构,核心组件就那么几个。咱们一个一个说。

1.2.1 行情网关

行情网关是系统的眼睛。它负责从交易所接收实时行情,然后分发给策略引擎。

我个人习惯用多路复用的方式处理行情。什么意思?就是用一个线程同时监听多个交易所的行情流。比如CTP、XONE、LTS,每个都开一个TCP连接,然后用epoll或kqueue统一管理。

// 伪代码:行情网关核心逻辑
void*行情网关线程() {
    while (true) {
        // 使用epoll等待多个交易所的行情数据
        int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        for (int i = 0; i < nfds; i++) {
            if (events[i].data.fd == ctp_fd) {
                处理CTP行情();
            } else if (events[i].data.fd == xone_fd) {
                处理XONE行情();
            }
            // 行情数据直接写入共享内存,零拷贝
            写入共享内存(行情数据);
        }
    }
}

这里有个关键点:零拷贝。行情数据从网卡到策略引擎,中间不要做任何数据复制。我见过有人用消息队列传行情,结果延迟直接翻倍。

1.2.2 策略引擎

策略引擎是大脑。它接收行情,计算信号,生成订单。

策略引擎的设计,我建议用事件驱动模式。行情来了触发一个事件,策略逻辑在事件处理器里跑。这样延迟可控,也方便做回测。

核心原则:策略引擎里不要做任何阻塞操作。不要写数据库,不要发HTTP请求,不要打印日志到磁盘。这些操作都会让延迟从微秒级变成毫秒级。

我记得有个学员问我:「老师,我的策略引擎跑着跑着就卡住了,怎么回事?」我一看代码,他在策略里写了个Thread.Sleep(100)。嗯,这相当于在赛车里踩刹车。

1.2.3 交易网关

交易网关是手和脚。它负责把策略生成的订单发到交易所,并接收成交回报。

交易网关的设计要点是低延迟和可靠性的平衡。一方面,订单要尽快发出去;另一方面,不能丢单。

我常用的做法是:

  • 订单直接通过TCP直连交易所,不走中间件
  • 使用预分配的订单ID,避免生成ID时的延迟
  • 成交回报用回调函数直接通知策略引擎,不经过队列

注意:交易网关一定要做重连机制。交易所的服务器偶尔会断开连接,如果重连不及时,订单就发不出去了。我曾经因为重连逻辑写错了,导致一个策略在行情剧烈波动时断连了30秒,损失惨重。

1.2.4 风控模块

风控模块是刹车。它负责检查每一笔订单是否合规。

风控模块的位置很关键。放在策略引擎前面?还是后面?我建议放在交易网关前面。为什么?因为策略引擎可能出bug,生成错误的订单。风控模块在交易网关前拦截,可以避免错误订单发到交易所。

风控检查项一般包括:

  • 订单价格是否在合理范围内
  • 持仓是否超过限制
  • 下单频率是否过高
  • 资金是否充足

我的经验:风控模块的检查逻辑要极致优化。每个检查项最好在几十纳秒内完成。我见过有人用正则表达式检查订单价格格式,结果一个检查就花了1微秒。你想想看,如果每秒检查1000笔订单,光风控就吃掉1毫秒,这在高频交易里是不可接受的。

1.3 数据流与延迟分析

好了,组件都介绍完了。咱们看看数据是怎么流的,以及延迟都藏在哪。

下面这张图展示了典型的高频交易系统数据流:

交易所 行情网关 策略引擎 风控模块 交易网关 行情数据 行情数据 订单 通过 订单 成交回报 成交回报 延迟分析 行情网关: 1-5μs 策略引擎: 10-100μs 风控模块: 1-5μs 交易网关: 5-20μs 网络传输: 50-500μs 总延迟: 67-630μs (不含交易所撮合延迟)

从图上可以看出,延迟主要来自几个地方:

  1. 网络传输:从交易所到行情网关,从交易网关到交易所。这部分延迟取决于物理距离和网络质量。我建议把服务器托管在交易所机房,能省掉50-100微秒。
  2. 行情处理:行情网关解析数据包、写入共享内存。这部分一般1-5微秒。
  3. 策略计算:策略引擎跑信号逻辑。这部分差异最大,简单的均线策略可能10微秒,复杂的机器学习模型可能100微秒以上。
  4. 风控检查:每个订单过一遍风控规则。优化得好可以控制在1-5微秒。
  5. 订单发送:交易网关把订单编码成协议格式,通过TCP发送。这部分5-20微秒。

关键结论:整个链路的总延迟通常在67-630微秒之间。如果你做的是高频交易,目标是把这个数字压到100微秒以内。怎么做?

  • 用C/S架构,减少进程间通信
  • 用共享内存代替消息队列
  • 用FPGA加速行情解析
  • 把策略逻辑写成简单的数学公式,避免复杂计算

好了,第一章的内容就到这里。记住一句话:架构没有银弹,只有取舍。C/S架构快但耦合,微服务灵活但慢。选哪个,取决于你的交易频率和业务复杂度。

下一章咱们聊聊行情网关的详细实现,包括如何用C++写一个低延迟的行情接收器。到时候我会分享一些我在实战中踩过的坑,保证让你少走弯路。


专注资料整理