第一章:交易系统架构设计 — 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 数据流与延迟分析
好了,组件都介绍完了。咱们看看数据是怎么流的,以及延迟都藏在哪。
下面这张图展示了典型的高频交易系统数据流:
从图上可以看出,延迟主要来自几个地方:
- 网络传输:从交易所到行情网关,从交易网关到交易所。这部分延迟取决于物理距离和网络质量。我建议把服务器托管在交易所机房,能省掉50-100微秒。
- 行情处理:行情网关解析数据包、写入共享内存。这部分一般1-5微秒。
- 策略计算:策略引擎跑信号逻辑。这部分差异最大,简单的均线策略可能10微秒,复杂的机器学习模型可能100微秒以上。
- 风控检查:每个订单过一遍风控规则。优化得好可以控制在1-5微秒。
- 订单发送:交易网关把订单编码成协议格式,通过TCP发送。这部分5-20微秒。
关键结论:整个链路的总延迟通常在67-630微秒之间。如果你做的是高频交易,目标是把这个数字压到100微秒以内。怎么做?
- 用C/S架构,减少进程间通信
- 用共享内存代替消息队列
- 用FPGA加速行情解析
- 把策略逻辑写成简单的数学公式,避免复杂计算
好了,第一章的内容就到这里。记住一句话:架构没有银弹,只有取舍。C/S架构快但耦合,微服务灵活但慢。选哪个,取决于你的交易频率和业务复杂度。
下一章咱们聊聊行情网关的详细实现,包括如何用C++写一个低延迟的行情接收器。到时候我会分享一些我在实战中踩过的坑,保证让你少走弯路。