Ruankao System Analyst (Senior) study materials
Ruankao System Analyst (Senior) study resources

零售订单域微服务拆分:一致性方案与组织约束的取舍

Ruankao System Analyst (Senior) · Put your knowledge to work in context.

All case studies

零售订单域微服务拆分:一致性方案与组织约束的取舍

某连锁零售企业计划把单体ERP中的订单域重构为微服务。现状:Oracle单库,订单主表4.2亿行,日订单80万,大促峰值3000 TPS,大促期间订单库QPS约1.2万、写占比35%。下单需同时扣减库存、核销优惠券、发起支付,客户对订单查询的P99要求为500ms。业务规则是:库存允许短暂超卖,但必须在30分钟内冲正;支付渠道回调可能重复、可能乱序到达;优惠券严禁超发,一旦超发将引发客诉与赔付。订单状态现由数据库status字段维护,有12个状态和40余条if-else分支,缺少状态机约束,历史数据中存在状态回退记录。库存与订单当前共用同一数据库账号,跨表JOIN较多。IT部门共6人,其中2人没有分布式系统经验;运维仍以虚拟机和人工发布为主,没有容器平台,也没有自动化流水线。第三方支付渠道有3家,接口协议各不相同,回调验签逻辑被重复实现。此前两次重构尝试均因上线后对账不平而回滚。管理层要求6个月内完成拆分,且下一次大促期间不得停机;财务要求订单金额与支付流水每日对账,差异必须当日查清。

1. 判断6个月内全面微服务化是否可行,说明服务边界划分依据与拆分顺序,并给出判断标准。

Read the worked answer

结论:不可行,应按绞杀者模式渐进拆分。

依据不在技术,而在组织:6人团队中2人无分布式经验、无容器平台、无自动化发布、无链路追踪,故障定位平均4小时;而“大促不停机”恰恰要求最强的灰度与回滚能力。历史上两次重构都因对账不平回滚,说明团队尚未掌握跨服务数据一致性的验证方法。此时全面拆分,是把架构风险叠加在能力短板上。

边界划分依据:按业务能力与限界上下文,而不是按技术分层。三个核心不变量决定了边界--库存是“可售量不被超卖”,优惠券是“券不被重复核销”,订单是“交易状态机”。支付渠道协议各异、验签逻辑重复,应下沉为防腐层(ACL)统一封装,而不是自建一个支付微服务去承担资金状态。

拆分顺序(按风险与收益排序)

  1. 先拆读多写少、耦合弱的查询/报表与商品目录,用来验证网关、注册发现、链路追踪、配置中心等底座。
  2. 再拆优惠券:规则独立,可用唯一索引保证不超发,爆炸半径小。
  3. 然后库存,采用“新服务+旧库扣减”双跑过渡,逐步切换写入。
  4. 订单最后拆,因为它是事务协调者,且状态机需要先梳理干净(12个状态应收敛为一棵显式状态机,并清理历史回退数据)。

判断标准:每次拆分后必须能独立回滚、单体仍可对外提供服务、对账连续3天无差异,否则不得进入下一步。

2. 为“下单-扣库存-支付”链路选择一致性方案(本地消息表/Saga/TCC),并说明补偿与幂等设计。

Read the worked answer

先看业务约束再选型

  • 库存允许短暂超卖、30分钟内冲正:最终一致可接受,不必上强锁。
  • 优惠券严禁超发:需要硬约束。
  • 支付回调可能重复或乱序:必须幂等+状态机。

方案组合(不追求全链路一种模式)

  • 下单主流程用编排式Saga:跨3个服务、流程长、补偿语义需要可见可审计。
  • 库存用“预占+确认/释放”两段式:预占写库时用update ... set 可售=可售-n where 可售>=n原子条件更新,杜绝超卖;30分钟未确认由定时任务释放生成冲正单,正好对上业务允许的窗口。
  • 优惠券不放进Saga:在优惠券库内用唯一索引(券ID+订单ID)由单库本地事务核销,失败即整单回滚,用数据库的强约束解决“严禁超发”,比补偿可靠。
  • 支付回调:建回调流水表,以渠道流水号+渠道标识为唯一键做幂等;用状态机版本号丢弃乱序的过期事件,回调只驱动状态迁移,不直接改金额。

补偿与兜底:每个正向动作必须有可重复执行的逆向动作;补偿以业务单号+动作类型做唯一键保证幂等;补偿失败进人工干预队列并告警;每日对账核对订单、库存、支付三方流水,差异超阈值即冻结相关账户。

不选TCC的理由:三个服务都要实现Try/Confirm/Cancel,Confirm失败仍需兜底,开发与运维成本对6人团队过高;TCC适合资源预留语义强、响应时间敏感的短事务,而这里是长流程。

3. 在无容器平台、运维能力有限的约束下,给出架构治理与发布策略,并说明什么情况下应主动停止拆分。

Read the worked answer

治理优先于拆分数量

  • 可观测性先行:第一个服务上线前就要有TraceID贯穿(建议直接以订单号为关联键)、结构化日志集中采集、核心接口RED指标。没有这些,拆得越多越查不清,4小时的定位时间只会更长。
  • 发布:无容器平台时,用“虚拟机+负载均衡摘挂+双版本并行”实现蓝绿;配置外置到配置中心,避免改配置就要发版;数据库变更与应用发布分离,先兼容后清理。
  • 数据边界:禁止跨服务直连数据库,取消共享账号;服务各自独立schema,为将来分库留路;跨服务查询走API或CDC事件。
  • 组织:设一名架构负责人和一名SRE角色;2名无经验成员采用结对+演练补课;从“杀一个实例”开始做混沌演练,逐步到“注入支付回调重复”。
  • 止损线必须提前写死:错误率>1%持续5分钟、P99翻倍、对账差异不可解释,任一触发即回滚;大促期间只做灰度,不做拆分上线,写入发布日历。

应主动停止的信号:底座指标不可得、对账连续不通过、团队无人能独立处理一次线上故障。此时停止拆分不是失败,而是避免把单体的问题变成分布式的问题--分布式系统不会减少复杂度,只会把复杂度转移到网络和运维上。