3、自动化系统架构设计:分层架构、微服务与消息队列

做市业务的清算结算,说白了就是一场与时间赛跑的「对账游戏」。

我入行那会儿,系统还是单体架构。每天凌晨跑批,十几个模块挤在一个进程里。哪个环节挂了,整个清算就卡死。运维同事半夜打电话叫醒我,说「哥,又堵了」——那种感觉,真不想再体验第二次。

所以后来设计自动化系统,我脑子里就三个关键词:解耦、弹性、可观测。今天咱们就聊聊,怎么用分层架构、微服务和消息队列把这三点落地。

3.1 分层架构:各司其职,别越界

我习惯把系统切成三层。每层只干自己的活,不越界。这样出了问题,定位也快。

核心原则:上层依赖下层,下层不依赖上层。数据流单向流动。

3.1.1 数据层

这一层负责「存」和「取」。说白了,就是跟数据库、缓存、文件系统打交道。

  • 关系型数据库:存交易流水、持仓、账户余额。我一般用 MySQL 或 PostgreSQL,分库分表是常态。
  • 缓存:Redis 扛高频查询。比如实时持仓快照,放 Redis 里,别每次都查库。
  • 消息持久化:清算过程中的中间状态,我习惯写进消息队列的持久化日志里。万一崩了,能从断点续传。

嗯,这里要注意:数据层的设计一定要考虑「幂等性」。我曾经因为重复消费导致持仓多算了一倍,排查了整整一个通宵。后来所有写入操作都加了唯一键约束,才彻底解决。

3.1.2 逻辑层

这是核心。清算规则、费用计算、净额轧差、风险校验……全在这层。

我个人的习惯是:把每个业务规则封装成独立的「处理器」。比如「计算交易费用」是一个处理器,「计算持仓盈亏」是另一个。它们之间通过事件驱动,互不干扰。

举个例子:

// 伪代码:清算规则链
public class SettlementRuleChain {
    private List<RuleProcessor> processors;
    
    public void execute(SettlementContext context) {
        for (RuleProcessor processor : processors) {
            if (!processor.process(context)) {
                // 某个规则失败,终止清算
                log.error("规则 {} 执行失败", processor.getName());
                break;
            }
        }
    }
}

你想想看,如果所有规则写在一个大方法里,改一个地方就得全量回归测试。拆成链式调用,新增规则只需要加一个处理器,多清爽。

3.1.3 展示层

这一层是给运营和风控同事看的。我见过太多系统,后端逻辑写得漂亮,前端却一团糟——数据对不上、刷新不及时、操作路径反人类。

我的经验是:展示层只做「呈现」和「交互」,不做任何业务计算。

  • 清算进度实时展示:用 WebSocket 推数据,别让用户手动刷新。
  • 异常告警高亮:红色标出,点击后直接跳转到对应的日志或数据详情。
  • 操作留痕:谁在什么时间做了什么操作,全部记录。方便事后审计。

小技巧:展示层的数据模型,最好跟后端的数据模型分开。前端需要的是「展示视图」,后端给的是「业务实体」。中间加一层 DTO 转换,能避免很多耦合问题。

3.2 微服务设计:拆得合理,合得优雅

微服务不是拆得越碎越好。拆得太细,服务间通信成本高得吓人;拆得太粗,又回到单体老路。

我一般按「业务边界」来拆。做市清算结算,我拆成这几个服务:

服务名称 职责 数据存储
交易接入服务 接收交易所/对手方的成交回报 MySQL + Redis
清算引擎服务 净额轧差、费用计算、持仓更新 MySQL + 消息队列
结算对账服务 与资金托管行/中央对手方对账 MySQL + 文件存储
风控校验服务 实时校验清算结果是否超限 Redis + 时序数据库
通知服务 推送清算结果给运营、风控、监管 消息队列 + 邮件/短信网关

每个服务独立部署、独立数据库。服务间通过 gRPC 或 RESTful API 通信。我个人偏爱 gRPC,性能好,而且强类型接口不容易出错。

避坑指南:我曾经把一个「清算引擎」拆成了「净额计算服务」和「费用计算服务」。结果两个服务需要频繁交换中间数据,网络开销比计算本身还大。后来合并成一个服务,反而更快。所以,高频交互的模块,别硬拆

3.3 消息队列选型:选对了,事半功倍

消息队列在清算系统里,主要干三件事:

  1. 异步解耦:交易接入后,直接扔进队列,清算引擎慢慢消费。
  2. 削峰填谷:盘后清算高峰,队列能缓冲压力。
  3. 可靠投递:确保每条交易都不丢、不重复。

市面上主流的消息队列,我基本都用过。说说我的感受:

选型 优点 缺点 适用场景
Kafka 高吞吐、持久化、分区有序 运维复杂、延迟稍高 大规模交易流水、日志采集
RabbitMQ 灵活的路由、低延迟、易运维 吞吐量不如 Kafka 实时通知、任务分发
RocketMQ 事务消息、延迟消息、金融级可靠 社区生态不如前两者 清算结算、对账、资金划拨
Pulsar 存算分离、多租户、云原生 学习曲线陡 大型金融云平台

我个人在清算场景里,最常用的是 RocketMQ。为什么?因为它的事务消息机制,能保证「本地事务」和「消息发送」的原子性。说白了,就是要么都成功,要么都回滚。这对资金类业务太重要了。

举个例子:

// 伪代码:事务消息示例
public void settleTrade(Trade trade) {
    // 1. 本地事务:更新数据库
    updateSettlementStatus(trade);
    
    // 2. 发送事务消息
    TransactionMQProducer producer = ...;
    Message msg = new Message("settle_topic", trade.toBytes());
    producer.sendMessageInTransaction(msg, null);
}

// 3. 消息消费者处理
public void onMessage(Message msg) {
    Trade trade = parseTrade(msg);
    // 执行后续清算逻辑
    calculateFee(trade);
    updatePosition(trade);
}

嗯,这里要提醒一句:消息队列不是银弹。如果业务逻辑强依赖顺序,比如「先减持仓、再加资金」,那就要用分区有序的队列(比如 Kafka 的 partition 或 RocketMQ 的 MessageQueue)。否则乱序消费会导致数据不一致。

3.4 架构总览:一张图说清楚

下面这张图,是我做清算系统架构设计时常用的分层结构。你可以看到数据从交易所流入,经过各层处理,最终输出清算结果。

做市清算结算自动化系统架构图 展示层 清算看板 | 异常告警 | 操作日志 | 报表导出 WebSocket 实时推送 · RESTful API 查询 逻辑层(微服务集群) 交易接入服务 清算引擎服务 结算对账服务 风控校验服务 gRPC 通信 · 独立部署 · 独立数据库 消息队列层 RocketMQ · 事务消息 · 削峰填谷 · 可靠投递 数据层 MySQL(交易流水/持仓/账户) | Redis(实时快照) 分库分表 · 读写分离 · 数据归档

你看,数据从下往上流,展示层只负责呈现。逻辑层通过消息队列与数据层解耦。每一层都能独立扩缩容——这就是分层架构的魅力。

最后说一句:架构设计没有标准答案。我给你的这套方案,是在多个做市商项目里打磨出来的。但你的业务场景可能不同,比如交易量级、合规要求、团队规模……这些都会影响最终选型。灵活调整,别硬套。


公众号:蓝海资料掘金营,微信deep3321