第三章:系统架构总览:微服务架构拆分、核心模块与通信方式
好,我们直接进入正题。这一章,我想跟你聊聊整个交易引擎的骨架长什么样。
很多人一上来就撸代码,结果做着做着发现模块之间像一团乱麻。我早期带团队时就吃过这个亏——一个撮合逻辑改了,清算那边跟着崩,风控也报警。说白了,就是架构没想清楚。
所以这一章,我们先画好蓝图。你想想看,一栋大楼的地基没打好,后面装修再漂亮也没用。
3.1 为什么必须拆成微服务?
交易系统不是普通的Web应用。它有几个硬伤:
- 高并发:一秒几万笔订单进来,单机扛不住
- 低延迟:撮合必须在毫秒级完成
- 高可用:宕机一分钟,损失可能就是几百万
- 业务复杂:撮合、清算、风控,每个环节都不同
如果全写在一个进程里,你想想看:
- 风控卡住了,撮合也得等着
- 清算出Bug,整个系统都得重启
- 想扩容?只能整体扩,浪费资源
所以,微服务拆分是必然选择。我个人习惯按业务边界切分,每个服务独立部署、独立扩容、独立演进。
核心原则:高内聚、低耦合。每个模块只做一件事,并且做到极致。
3.2 核心模块拆解
一个典型的分布式交易引擎,我一般拆成四个核心模块:
3.2.1 接入层(Gateway)
这是系统的门面。所有外部请求都先打到这。
它负责:
- 协议转换:把HTTP、WebSocket、TCP等不同协议转成内部统一的RPC调用
- 鉴权与限流:谁在调用?是不是合法用户?每秒能调多少次?
- 请求路由:把订单请求转发到对应的撮合引擎实例
- 连接管理:维护长连接,推送行情和成交回报
我在项目中遇到过一个问题:接入层如果处理太慢,会直接拖垮整个系统。后来我们用了Netty做IO框架,配合无锁队列,才把单机吞吐提到10万+。
避坑指南:我曾经把鉴权逻辑写在接入层里,结果每次请求都查一次数据库,延迟直接飙到50ms。后来改成本地缓存+定期刷新,延迟降到1ms以内。
3.2.2 撮合引擎(Matching Engine)
这是整个系统的核心。说白了,就是「谁想买、谁想卖,帮他们配对」。
它需要:
- 维护订单簿:买盘和卖盘,按价格时间排序
- 执行撮合逻辑:价格优先、时间优先
- 生成成交记录:谁买了多少、谁卖了多少、成交价是多少
嗯,这里要注意:撮合引擎是有状态的。订单簿不能丢,一旦宕机恢复,必须能从快照+日志重建。
我建议把撮合引擎设计成单线程模型。为什么?因为撮合本质上是顺序操作,多线程反而会引入锁竞争,降低性能。我在一个项目中试过多线程撮合,结果延迟反而比单线程高了3倍。
警告:千万不要在撮合引擎里做IO操作!比如查数据库、发网络请求。这些操作会阻塞线程,导致撮合延迟飙升。所有IO操作都应该异步化。
3.2.3 清算引擎(Clearing Engine)
撮合完了,钱和资产怎么划转?这就是清算引擎的事。
它负责:
- 资金结算:买方扣钱、卖方加钱
- 资产划转:买方加资产、卖方扣资产
- 手续费计算:按规则扣手续费
- 对账:确保账目一致
清算引擎是最终一致性的典型场景。撮合引擎可以很快,但清算必须保证数据绝对正确。我习惯用事件驱动的方式:撮合引擎生成成交事件,清算引擎消费事件,异步处理。
你想想看,如果清算和撮合同步执行,一笔成交要等清算完才能返回,那延迟得多高?
3.2.4 风控引擎(Risk Engine)
风控是交易系统的「刹车」。没有它,系统可能被恶意用户搞崩。
它负责:
- 事前风控:下单前检查用户余额、持仓、限价等
- 事中风控:监控异常交易行为,比如频繁撤单、自成交
- 事后风控:分析历史数据,发现潜在风险
我在项目中遇到过一个大坑:风控引擎如果处理太慢,会拖慢整个下单流程。后来我们把风控规则做成可配置的,并且用规则引擎(比如Drools)来执行,才把单次风控检查时间控制在1ms以内。
关键点:风控引擎必须独立部署,不能和撮合引擎混在一起。否则风控出问题,撮合也跟着挂。
3.3 模块间通信方式
模块拆开了,怎么通信?这是架构设计的关键。
我一般用三种方式:
| 通信方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 同步RPC(gRPC/Thrift) | 接入层→撮合引擎 | 低延迟、强一致性 | 耦合度高 |
| 异步消息(Kafka/RocketMQ) | 撮合引擎→清算引擎 | 解耦、削峰填谷 | 最终一致性 |
| 事件总线(Redis Pub/Sub) | 行情推送、状态通知 | 实时性高 | 可靠性一般 |
具体来说:
- 接入层到撮合引擎:我用gRPC。为什么?因为下单请求需要实时响应,gRPC基于HTTP/2,延迟低、性能好。
- 撮合引擎到清算引擎:我用Kafka。撮合引擎只管生成成交事件,清算引擎异步消费。这样即使清算引擎挂了,消息也不会丢。
- 风控引擎:我把它设计成「旁路」模式。下单时,接入层先调风控接口检查,通过后再转发给撮合引擎。这样风控不会成为瓶颈。
个人经验:我曾经用RabbitMQ做撮合和清算之间的通信,结果有一次消息堆积,清算延迟了10分钟。后来换成Kafka,配合分区机制,再也没出过问题。Kafka的持久化和重试机制,在金融场景下真的很稳。
3.4 整体架构图
说了这么多,不如一张图来得直观。下面是我画的一个简化版架构图:
这张图展示了核心模块之间的通信关系。你可以看到:
- 接入层通过gRPC调用撮合引擎,同时旁路调用风控引擎
- 撮合引擎通过Kafka异步通知清算引擎
- 所有模块都访问数据库,但访问方式不同
3.5 架构设计的一些思考
最后,我想分享几个我在实际项目中踩过的坑:
- 不要过度拆分。我见过有人把撮合引擎拆成「订单接收服务」和「撮合执行服务」,结果两个服务之间通信延迟比撮合本身还高。微服务的粒度要适中。
- 通信方式要统一。团队里有人用gRPC,有人用HTTP,有人用消息队列,最后维护成本极高。我建议一个系统内最多用两种通信方式:同步用gRPC,异步用Kafka。
- 监控和链路追踪必须跟上。微服务拆了之后,一个请求可能经过5-6个服务。没有链路追踪,出了问题你根本不知道在哪。我习惯用Jaeger做全链路追踪。
重要提醒:架构设计没有银弹。你看到的每个方案,都是权衡的结果。比如同步RPC延迟低但耦合高,异步消息解耦好但延迟高。选哪个?取决于你的业务场景。
好了,这一章我们画好了蓝图。下一章,我会带你深入撮合引擎的核心——订单簿的设计与实现。那是整个系统最硬核的部分,准备好了吗?
公众号:蓝海资料掘金营,微信deep3321