4. 架构分层设计:接入层、逻辑层、数据层的分层策略、各层的高可用目标

做市商系统,说白了就是一台高速运转的印钞机——前提是它不能停。

我见过太多团队,一上来就追求极致的低延迟,结果系统三天两头出故障。你想想看,一个每秒处理几万笔订单的系统,如果因为架构耦合太紧导致雪崩,那损失可不是闹着玩的。

所以,分层设计是我做架构时第一个要敲定的事。今天咱们就聊聊接入层、逻辑层、数据层这三层怎么拆,每层的高可用目标又是什么。

4.1 为什么必须分层?

不分层的架构,就像把所有的鸡蛋放在一个篮子里。一旦某个环节出问题,整个系统就瘫了。

我个人习惯把做市商系统拆成三层:

  • 接入层:负责跟外部打交道,比如交易所、行情源、客户端。
  • 逻辑层:核心业务逻辑,比如定价、风控、订单管理。
  • 数据层:负责数据持久化,比如订单簿、账户余额、历史记录。

每一层各司其职,互不干扰。这样出了问题,我们能快速定位,也能单独做高可用。

核心原则:层与层之间通过轻量级协议通信,比如gRPC或者消息队列。千万别搞成强依赖,否则分层就失去了意义。

4.2 接入层:守好大门

接入层是系统的脸面。所有外部请求都从这里进来。

它的高可用目标很明确:连接不断、请求不丢、流量可控

4.2.1 连接管理

做市商系统通常需要跟多个交易所保持长连接。我记得有一次,某个交易所的API突然升级,导致我们的连接全部断开。那叫一个惨,订单直接卡死。

从那以后,我要求接入层必须做到:

  • 多活连接:每个交易所至少建立2条独立连接,一条主用,一条备用。
  • 心跳检测:每100ms发一次心跳,连续3次没响应就自动切换。
  • 连接池化:复用连接,避免频繁创建销毁带来的开销。

4.2.2 流量整形

行情数据有时候会突然暴增,比如重大新闻发布时。如果接入层不做限流,逻辑层瞬间就会被冲垮。

我常用的策略是:

  • 令牌桶限流:控制每秒进入逻辑层的请求数。
  • 请求去重:同样的订单请求,只处理一次。
  • 熔断降级:如果逻辑层响应超时,接入层直接返回失败,避免堆积。
避坑指南:我曾经遇到过限流参数设置太死板,导致正常行情也被拦截。后来改成动态限流,根据系统负载自动调整阈值,效果好了很多。

4.3 逻辑层:核心大脑

逻辑层是系统最复杂的一层。定价、风控、订单路由都在这里完成。

它的高可用目标:计算准确、状态一致、故障自愈

4.3.1 无状态设计

逻辑层最好设计成无状态的。什么意思?就是每个节点不保存任何本地状态,所有状态都丢到数据层去。

这样做的好处是:

  • 水平扩展:加机器就能提升处理能力。
  • 故障转移:一个节点挂了,另一个节点直接接管,没有状态丢失。

你想想看,如果逻辑层节点保存了订单的中间状态,一旦宕机,那些订单就丢了。这在做市商系统里是绝对不能接受的。

4.3.2 幂等性保障

网络抖动是常态。同一个订单请求可能被重复发送。

逻辑层必须保证幂等性:同样的请求,处理一次和处理多次,结果一样。

我通常的做法是:

  • 每个请求带一个全局唯一的ID。
  • 逻辑层处理前先查一下这个ID是否已经处理过。
  • 如果处理过,直接返回上次的结果。
注意:幂等性不能只靠数据库的唯一索引。因为在高并发下,唯一索引也可能出现重复插入的异常。最好用分布式锁或者乐观锁来兜底。

4.4 数据层:持久化基石

数据层是系统的最后一道防线。所有订单、账户、行情数据最终都要落盘。

它的高可用目标:数据不丢、读写分离、快速恢复

4.4.1 主从复制与分片

单库单表肯定扛不住做市商系统的写入量。我一般用分片+主从复制:

  • 分片:按交易对或者用户ID把数据分散到多个数据库。
  • 主从复制:每个分片至少一主一从,主库负责写,从库负责读。

这样即使某个分片的主库挂了,从库能秒级切换成主库,业务几乎不受影响。

4.4.2 数据一致性

做市商系统对数据一致性要求极高。尤其是账户余额,绝对不能出现对不上账的情况。

我常用的方案是:

  • 两阶段提交:对于关键操作,比如扣款和下单,必须保证原子性。
  • 对账机制:每隔一段时间,用离线任务把数据库里的订单和交易所的成交记录做一次比对。
个人经验:我曾经因为数据库主从延迟,导致风控系统读到了过期的余额数据,差点让系统超卖。后来我强制风控操作必须读主库,才彻底解决了这个问题。

4.5 分层架构的核心逻辑图

下面这张图,是我做分层设计时经常用的参考。它清晰地展示了三层之间的协作关系:

接入层 连接管理 | 流量整形 | 协议转换 高可用目标:连接不断、请求不丢、流量可控 gRPC/消息队列 逻辑层 定价引擎 | 风控系统 | 订单路由 高可用目标:计算准确、状态一致、故障自愈 数据库/缓存 数据层 主从复制 | 分片存储 | 对账机制 高可用目标:数据不丢、读写分离、快速恢复

4.6 各层之间的协作要点

分层不是把系统拆开就完事了。层与层之间的协作,才是高可用的关键。

  • 超时控制:接入层调用逻辑层时,必须设置超时时间。我一般设500ms,超过就熔断。
  • 异步解耦:逻辑层写入数据层时,尽量用异步方式。比如订单落库,先写到消息队列,再由消费者慢慢处理。
  • 降级策略:如果数据层挂了,逻辑层能不能降级?比如暂时不更新订单簿,只做报价。这个需要提前设计好。
一个小技巧:我习惯在每一层都埋一些关键指标,比如请求量、延迟、错误率。这样一旦出问题,能快速判断是哪一层出了状况。

好了,关于分层设计,今天就聊这么多。记住,分层不是为了炫技,而是为了在系统出问题时,我们能睡得着觉。

专注资料整理