知易通
第二套高阶模板 · 更大气的阅读体验

微服务事务处理实战:一家电商公司的订单难题

发布时间:2026-01-04 03:41:42 阅读:63 次

老张是某中型电商平台的技术负责人,最近他们系统出了个怪问题:用户下单后,库存扣了,订单也生成了,但支付状态却没更新。更离谱的是,财务对账时发现,每天都有几单钱收了,但订单显示失败。

拆分之后的烦恼

平台原本是个单体应用,去年重构成了微服务架构。订单、库存、支付、用户各自独立部署,开发快了,运维也灵活了。可一到涉及多个服务的数据操作,问题就来了。

比如下单这个流程,要调用三个服务:创建订单、扣减库存、发起支付。理想情况下,三步都成功才算完成。可一旦中间出问题,比如支付系统超时,前两步已经执行,怎么回滚?

试过最简单的方案

一开始他们用了“事后补偿”的土办法:如果支付失败,后台定时任务去查,再手动回退库存和订单状态。结果高峰期延迟严重,补单脚本自己还出bug,客服电话被打爆。

后来想到用消息队列解耦。订单服务发一条“待支付”消息,库存先锁定,等支付结果回来再决定是扣款还是释放。这招有点用,但消息丢了怎么办?重复消费怎么防?还得加一层幂等判断。

if (paymentRecordService.isProcessed(orderId)) {
return; // 已处理,直接跳过
}
// 执行实际业务逻辑

最终落地的可靠方案

团队调研了一圈,最后选了基于 Saga 模式的分布式事务框架。每个操作都有对应的补偿动作,比如“扣库存”对应“回退库存”,“创建订单”对应“取消订单”。

流程变成这样:订单服务启动 Saga 协调器,依次调用各服务。任何一步失败,协调器触发反向操作链。虽然不能保证强一致性,但在大多数场景下,最终一致就够了。

他们还把关键链路加上了 TCC(Try-Confirm-Cancel)模式。比如库存服务,先 Try 阶段冻结数量,Confirm 阶段才真正扣减,Cancel 就释放冻结。虽然开发成本高点,但资金类操作必须稳。

现在系统上线三个月,异常订单从每天十几单降到近乎为零。运维同事终于不用半夜爬起来手动修数据了。

微服务不是银弹,拆得越细,事务问题就越突出。没有万能解法,得根据业务权衡:对一致性要求高的用 TCC,能接受短暂不一致的走 Saga,实在简单就靠消息+重试兜底。

技术选型就像做饭,火候和食材搭配比菜谱写得漂亮更重要。