论分布式事务及其解决方案

论分布式事务及其解决方案

随着微服务、分库分表架构广泛落地,单一数据库本地事务无法覆盖跨服务、跨库的数据更新场景,分布式事务成为保障系统数据一致性的核心技术。分布式事务受网络抖动、服务宕机、分片隔离等因素影响,极易出现数据不一致、脏数据、事务悬挂等问题。本文结合本人参与的电商订单微服务平台项目,介绍 2PC、TCC、Saga、本地消息表四种主流分布式事务方案的实现原理,阐述项目中基于本地消息表 + TCC 混合方案落地分布式事务的完整流程,分析落地过程中出现的消息丢失、空回滚、幂等失效等问题并给出对应优化方案,最后对比各类方案适用场景,总结分布式事务落地实践经验。

一、项目概述与本人主要工作

1. 项目背景

本人 2024 年参与某中型电商平台订单履约微服务系统的架构设计与开发工作。平台采用 Spring Cloud 微服务架构,业务按领域拆分为用户服务、商品库存服务、订单服务、支付服务、物流仓储服务,数据库采用 MySQL 分库分表,各服务独立私有库,不存在跨库本地事务能力。 核心业务流程:用户下单时,需同时完成扣减商品库存、生成订单记录、创建支付流水、锁定仓储发货单四大跨服务操作;任意环节失败必须保证全部数据同时回滚,不能出现 “库存已扣、订单未创建”“支付成功但库存未减” 的数据不一致问题。初期项目仅依靠本地事务,多次出现服务宕机导致的数据错乱,产生大量售后对账工单,因此引入分布式事务解决跨服务一致性问题。

2. 本人承担主要工作

  1. 梳理下单、退款、取消订单三大核心分布式业务流程,梳理各服务数据交互边界,梳理一致性异常场景;
  2. 调研 2PC、TCC、Saga、本地消息表四种分布式事务方案,完成方案选型对比,输出技术选型报告;
  3. 主导基于 RocketMQ 本地消息表 + TCC 混合分布式事务框架的代码落地,编写事务幂等、防悬挂、消息补偿基础组件;
  4. 线上灰度上线后,定位并解决消息丢失、重复消费、空回滚、补偿任务堆积等线上一致性故障;
  5. 设计定时任务对账补偿平台,实现每日分布式数据自动校验,修复未自动补偿的脏数据。

二、四种主流分布式事务解决方案及处理机制

(一)2PC(两阶段提交)

2PC 是强一致性分布式事务方案,依托协调者(Coordinator)与多个参与者(Participant)完成事务提交,分为准备阶段、提交阶段。

  1. 第一阶段(准备阶段):协调者向所有参与事务的数据库 / 服务发送准备请求;参与者执行本地事务、锁定资源,但不提交,返回成功 / 失败状态给协调者。
  2. 第二阶段(提交 / 回滚阶段):协调者收集所有参与者反馈:
    • 全部返回成功:下发提交指令,各参与者提交本地事务、释放锁;
    • 任一参与者失败 / 超时:下发回滚指令,所有参与者回滚本地事务,释放锁。优缺点:一致性强,对业务侵入极低;缺点是协调者宕机、参与者长时间锁定资源会造成阻塞,性能差,不适合高并发电商场景,多用于数据库层分布式事务(如 MySQL XA 事务)。

(二)TCC(Try-Confirm-Cancel)

TCC 属于补偿型、柔性事务,将业务拆分为三段自定义接口,完全由业务代码控制事务逻辑,无数据库锁阻塞。

  1. Try(预留资源):冻结 / 锁定业务资源,完成数据预操作,仅做预留,不真正扣减 / 新增;如库存预扣、订单预创建、支付资金冻结。
  2. Confirm(确认提交):所有服务 Try 阶段全部执行成功后,执行确认逻辑,正式提交业务数据,释放预留资源。
  3. Cancel(取消回滚):任意服务 Try 失败或超时,执行回滚逻辑,释放预留资源,恢复业务数据。核心特点:业务侵入性强,每个业务接口需手动实现三段逻辑;无长事务锁,并发性能高,一致性可控,适合核心资金、库存等高一致性要求场景。

(三)Saga 事务模式

Saga 是长事务柔性方案,分为编排式 Saga编排式 Saga,核心思想是 “正向操作 + 反向补偿操作”,无资源预留阶段。

  1. 流程规则:每个分布式操作对应一个补偿回滚操作;事务按顺序执行正向步骤,某一步失败时,逆序执行前面所有成功步骤的补偿逻辑,撤销已提交数据。
  2. 两种实现方式:
    • 编排式:中央事务调度器统一管理流程,下发执行 / 补偿指令;
    • 编排式:各服务通过事件消息联动,自主触发补偿,无中心调度器。优缺点:无需资源锁定,业务侵入中等;无法隔离脏读,中间步骤数据已提交,存在短期不一致,适合长流程、低实时一致性要求的业务(如物流履约、售后退款)。

(四)本地消息表(可靠消息最终一致性)

属于异步柔性事务,基于本地数据库消息表 + 消息队列实现最终一致性,是互联网高并发场景最常用方案。

  1. 核心执行机制: ① 本地事务:业务主操作与写入消息记录存入同一本地数据库事务,保证业务数据和消息记录同时落库; ② 消息投递:独立定时任务读取本地消息表,将消息发送至 MQ;发送失败则重试,记录投递状态; ③ 消费处理:下游服务消费消息,执行分支业务;消费成功则回调更新本地消息表状态为已完成;消费失败则 MQ 重试,或定时任务补偿重发; ④ 死信处理:多次消费失败的消息转入死信表,人工 / 定时对账修复。优缺点:对业务侵入小、并发性能高、架构简单;仅保证最终一致性,中间状态数据不一致,适合跨服务异步通知场景(订单通知库存、积分发放、短信推送)。

三、项目分布式事务实施过程、遇到的问题及解决方案

1. 方案选型与落地实施过程

本电商下单流程兼具强一致性要求(库存、资金不能超扣)高并发吞吐量需求,单一方案无法满足业务:

  • 2PC 性能差,高并发下单会出现数据库锁等待,直接排除;
  • 纯 Saga 无资源锁定,存在超卖风险,不适合库存扣减;
  • 纯 TCC 全流程开发成本高,下游物流、积分通知无需强实时一致; 最终确定TCC 处理核心库存、订单、支付强一致流程,本地消息表处理积分、短信、物流通知异步分支的混合分布式事务方案,实施流程如下:
  1. 阶段 1:TCC 核心事务改造订单、库存、支付服务分别实现 TCC 三段接口:

    • Try:库存预扣减、订单预生成、支付资金冻结;全部 Try 执行成功才进入 Confirm;任一失败调用 Cancel 释放资源;
    • Confirm:正式扣减库存、确认订单、完成资金扣款;
    • Cancel:恢复预扣库存、删除预订单、解冻资金。 使用 Spring Cloud TCC 框架管理事务协调,记录全局事务日志,记录各服务阶段状态。
  2. 阶段 2:本地消息表异步分支处理核心 TCC 事务 Confirm 成功后,在订单服务本地事务写入消息表,记录 “发放积分、推送物流通知” 消息;定时任务轮询未发送消息,投递 RocketMQ;积分、物流服务消费消息完成异步业务,消费成功后回调更新消息状态。

  3. 阶段 3:补偿与对账兜底机制搭建搭建定时补偿任务:① 扫描 TCC 悬挂事务(Try 成功未 Confirm/Cancel),自动触发 Cancel 回滚;② 扫描本地消息表未投递、未消费消息,重试发送;每日凌晨全量对账,对比订单、库存、支付数据,自动修复无法自动补偿的脏数据。

2. 落地过程遇到的问题及解决办法

问题 1:TCC 空回滚、事务悬挂问题

现象:库存服务 Try 接口因网络超时未收到协调者请求,协调者判定 Try 失败触发 Cancel,库存服务无对应 Try 记录,执行 Cancel 时报错;部分服务 Try 成功后服务宕机,事务长期停留 Try 状态,库存资源持续冻结导致超卖。 解决方案:

  1. 全局事务 ID 作为唯一幂等标识,每个服务本地存储事务操作记录;执行 Cancel 前先查询是否存在 Try 记录,无记录直接返回成功,避免空回滚;
  2. 增加事务超时时间,定时任务扫描超过 10 分钟未结束的 TCC 事务,自动执行 Cancel 释放冻结库存,解决事务悬挂。
问题 2:本地消息表消息丢失、重复消费

现象:定时任务发送 MQ 消息时服务宕机,消息仅写入本地表未投递,下游物流、积分业务未执行;MQ 重试投递导致下游重复扣减积分、重复创建物流单。 解决方案:

  1. 消息投递采用状态机:待发送、投递中、已完成、死信;定时任务发送前将消息状态改为投递中,投递成功更新为已完成,宕机未投递的 “投递中” 消息下次定时自动重发,杜绝消息丢失;
  2. 下游消费服务基于全局订单号做幂等控制,消费前查询本地消费记录,已处理消息直接返回,防止重复执行业务。
问题 3:高并发下 TCC 协调者单点压力大

现象:大促下单峰值,全局 TCC 协调服务请求堆积,出现协调超时,大量事务触发回滚,影响下单成功率。 解决方案:

  1. 拆分全局事务日志分表存储,降低单表查询压力;
  2. 协调服务集群部署,引入注册中心负载均衡,增加事务协调线程池;
  3. 非核心异步分支剥离至本地消息表 MQ 异步处理,减少 TCC 事务参与节点,缩短 TCC 两阶段执行耗时。
问题 4:补偿任务堆积,对账修复延迟

现象:夜间大量失败事务补偿任务集中执行,数据库 CPU 冲高,对账数据修复滞后。 解决方案:

  1. 补偿任务增加分片限流,按订单 ID 哈希分片分散执行;
  2. 区分实时补偿与凌晨离线对账:短时失败消息实时重试,长时间未修复脏数据交由凌晨低峰时段全量对账处理,错开业务高峰。

四、总结

分布式事务不存在通用最优方案,强一致性、性能、开发成本三者无法同时兼顾:2PC 适合低并发、强一致数据库场景;TCC 适合资金、库存等核心高一致性业务;Saga 适合长流程、允许短期不一致的业务;本地消息表适合高并发异步通知场景。 本次电商项目通过 TCC + 本地消息表混合方案,兼顾核心流程强一致与异步分支高并发性能,同时配套幂等、定时补偿、全量对账兜底机制,解决了网络故障、服务宕机带来的数据不一致问题。分布式事务落地不能仅依赖框架,必须结合业务场景做分层方案设计,并建立完整的监控、补偿、对账兜底体系,才能保障分布式系统长期稳定的数据一致性。