架构师修行录

订单中台架构演进设计

大家好,我是Jensen。

最近给订单团队设计了一个订单中台架构演进方案,分享给大家。

一、现状与痛点

  • 目前已经有大中台的概念,客户下单/退单都走order下单服务,并同步数据到sms销售系统,但具体接入没有标准,容易在迭代过程中发生偏离
  • 下单系统和销售系统分离,两个服务对同一笔单都有操作入口,会有并发风险,且双库数据同步存在延迟
  • ERP后台操作订单时,所有订单都在同一个菜单下,订单主表膨胀至几百个字段。按照不断做加法的策略,2年后可能会膨胀至上千个字段,JOIN连接查询上百个
  • 需确定未来接入新订单的形式,统一接入标准、架构风格、存储策略等
  • 需明确订单中台现有职责划分,让新业务能够快速接入

二、订单存储策略

主档信息核心字段标准化

在DDD四色建模法中,订单属于时标模型,用户在下单的一刻就应持久化当时的状态(快照冗余),所以对于用户昵称、商品名称等字段,应存到主档信息中,而不是在查询时去实时关联用户表、商品表,这样能减少大量JOIN连接查询。

假设需要在ERP后台通过用户昵称查询该用户的订单,由于用户昵称可能会在下单后修改,那历史的订单就无法通过修改后的昵称查出来。

推荐的做法是在前端做一个根据各种条件查出用户的控件(如昵称、手机号等),取出客编后再传至后端查询,其他更复杂的查询方式也可以通过这种方式分解复杂度。

扩展信息存储方案

在订单中台,需要在同一张订单表扩展不同的业务,难点在于如何设计一个能满足不同类型订单的个性化存储方案。

方案1(现状):订单类型+垂直扩展表

订单表按照业务垂直拆分为多张订单扩展表,扩展表与订单类型是一对多的关系,如果新的订单类型不能在现有扩展表上加,那就再加新的扩展表解决。

优点:SQL关联查询、数据分析性能最优。

缺点:适用于业务范围有限的订单类型,如果不同类型的订单差异化过大,会导致垂直扩展表膨胀;新订单类型复用垂直扩展表,可能会影响现有业务,需要特别注意。

拆分垂直扩展表需要一定的抽象,尽量能满足后续更多订单类型,以减少垂直扩展表的数量级与JOIN查询。

方案2:订单类型+订单宽表

优点:简单粗暴,SQL关联查询、数据分析性能最优。

缺点:如果不同类型的订单差异化过大,会导致订单字段迅速膨胀;会存在多个字段缺失;新增订单类型时,必须修改表结构。

目前订单类型只有16种,主档已有几百个字段,按照此种方式,字段会继续膨胀,不是订单中台的好做法。

方案3:订单类型+JSON类型扩展

使用JSON字段(MySQL 5.7+)或MongoDB存储动态属性。

例如:

  • 外卖订单的extras:{"delivery_address": "北京朝阳", "rider_id": 1001}
  • 电商订单的extras:{"sku_list": [{"id":101, "qty":2}], "invoice_type": "电子"}

优点:新的订单类型不需要改表结构、单表操作。

缺点:JSON内存储的字段对于后台条件查询、SQL数据分析不友好。

方案4:订单类型+订单扩展KV表

设计一个订单扩展元数据表order_ext_meta(或在代码层面通过枚举定义):

order_type
field
remark
field_type
1(在线下单)
ext1
扩展字段一
STRING

再设计一个订单扩展表order_ext:

order_id
key
value(varchar)
SO123
ext1
扩展值一
SO123
ext2
扩展值二

查询时需做行转列,如SQL层面(MySQL的动态SQL、PostgreSQL的crosstab函数),或代码层面转换。

优点:扩展字段可做JOIN查询,能通过SQL分析完整的信息;新增订单类型时,只需要维护该订单类型的元数据即可,不需要修改表结构。

缺点:双表操作,查询复杂度上升;value类型固定,需要在应用校验再落库。

三、订单中台最终架构

分两个阶段实施:

Image

说明:客户下单/退单/查单在下单系统统一收口,先从订单中台拆出查询逻辑到查单系统,同时下单系统能力下沉至订单中台。

Image

说明:统一架构风格,下单系统作为小烟囱底座,与其他后端业务系统平级,业务系统直接对接订单中台下单/退单/改单接口;允许订单差异数据存到各自业务系统DB,需通过MQ更新业务系统DB的数据状态。

核心用例

  • 客户查单:C端网站 -> 业务系统 -> 业务系统DB读库,按需聚合中台订单数据
  • 客户下单/退单:C端网站 -> 业务系统 -> 业务系统DB写库 -> 订单中台 -> PolarDB写库
  • 运营查单:ERP运营工作台 -> 查单系统 -> PolarDB只读Proxy -> PolarDB读库 -> 按需聚合业务系统个性化订单数据
  • 运营改单:ERP运营工作台 -> 订单中台 -> PolarDB写库 -> 发布MQ领域事件 -> 业务系统各自监听自己的订单类型

职责边界划分

两个阶段都需要明确订单中台与业务系统的职责范围,避免订单中台演变到最后被架空,通用能力丢失。

功能模块订单中台业务系统
下单/退单
只提供给业务系统或开放平台
提供给 C 端网站和 ERP 运营工作台
下单/退单校验
只校验标准功能
校验个性化功能
客户查单
只提供给业务系统或开放平台
直接提供,按需聚合中台订单数据
运营查单
查单系统统一提供,按需聚合
查单系统统一提供,按需聚合
运营改单
改单后发送 MQ 通知业务系统异步更新
双写策略,写完本地库可调订单中台接口更新,若失败则回滚
自动取消策略
扫表拿到取消的订单进行关单,并发送 MQ 事件
下单时下发自动取消时间给订单中台,监听订单中台取消 MQ 事件,处理自己的逻辑
字段存储策略
只存标准字段,保留现有非标字段
存储差异化字段,标准字段按需冗余
支付结果通知
支付后发送支付结果通知 MQ 事件
监听支付结果通知 MQ 事件
订单状态机
只存标准订单状态
扩展个性化订单状态
订单收货信息
可选,传入订单收货详细信息
按需冗余
订单开票
可选,传入开票信息
按需冗余
生命周期管理
统一控制流转逻辑
可发指令给中台执行
仓储能力
可选,出入库、改库存
-
营销能力
可选,卡、券、积分等订单优惠,依赖会员、会员资产、商品体系
-
商品能力
支持商品/非商品订单创建
-
售后能力
发起售后、审批流
-
领域事件通知能力
发布通用订单领域事件
发布特定领域事件

客户交易正向主流程

Image

EOF

Image

作者:Jensen

专注分享程序员日常/架构技术/职场干货

Java老兵一枚,深耕电商/物联网/康美/AI等领域产品研发多年。

DDD4j开源框架作者,现任职某电商平台高级架构师。

关注回复“DDD”,免费领取DDD学习大礼包。

关注回复“进群”,我拉你进架构技术交流群。