分布式事务的几种落地模式

举报
yd_273762305 发表于 2026/11/09 04:03:48 2026/11/09
【摘要】 2PC、TCC、Saga、本地消息表、最大努力通知——五种分布式事务方案对比,附选型判断和三个实战经验。

单体应用里,一个 @Transactional 解决所有一致性问题。拆成微服务后,一个下单流程要跨订单服务、库存服务、账户服务——本地事务不管用了,得引入分布式事务。这篇文章梳理几种主流落地方案,以及它们各自适合的边界。

先明确:一致性有强弱之分

讨论方案前必须区分两种一致性:

- 强一致性:任何时刻所有节点看到的数据都一致。代价是性能,通常需要锁或同步等待。

- 最终一致性:允许短暂不一致,但最终会收敛到一致状态。代价是业务上要处理中间态。

大多数互联网业务(下单、支付、发货)其实只需要最终一致——用户能接受「下单后几秒内库存才扣减」,但不能接受「多扣了钱」。只有金融核心账务这类场景才必须强一致。

方案一:2PC / XA(强一致,但很重)

两阶段提交。协调者先问所有参与者「能提交吗」(prepare),全票通过后再通知「提交」(commit)。

优点:数据库层面原生支持,业务代码几乎不用改。

缺点:同步阻塞(prepare 阶段所有参与者都要持锁等待);协调者单点;性能差(吞吐通常只有单库的 1/5~1/10)。

适用:跨库但同构的场景,并发量不大,比如内部管理系统的批处理。**互联网高并发场景基本不用**。

方案二:TCC(Try-Confirm-Cancel)

业务层面的两阶段。每个参与方提供三个接口:

- Try:预留资源(冻结库存、冻结金额),不真正扣减

- Confirm:确认执行(真正扣减)

- Cancel:回滚(释放预留)

// 库存服务的 Try
boolean tryDeduct(String orderId, int count) {
    // 冻结库存:available -= count, frozen += count
    return stockMapper.freeze(orderId, count) > 0;
}
// Confirm:frozen -= count
// Cancel:available += count, frozen -= count

优点:性能好(Try 阶段不长时间持锁);可控性强(业务自己定义预留和回滚逻辑)。

缺点:**改造成本最高**——每个参与方都要实现三个接口,还要处理空回滚、幂等、悬挂(Cancel 先于 Try 到达)这三大难题。

适用:资金类、库存类等强一致要求且并发高的核心场景。支付宝早期就是这么做的。

方案三:Saga(长事务拆分)

把一个大事务拆成一串本地事务,每个都有对应的补偿操作。任何一步失败,反向执行已完成步骤的补偿。

下单 → 扣库存 → 扣余额 → 创建物流单
          失败则 ← 补偿:加回库存
                     ← 补偿:加回余额

优点:无锁,性能好;天然适合长流程(比如跨天的审批流)。

缺点:**没有隔离性**——中间态对外可见。比如扣了库存但还没扣余额,这时用户查库存会看到已扣。需要业务层面设计「状态机」来屏蔽中间态。

适用:流程长、参与方多、能接受中间态的业务,如订单履约、旅行预订(机票+酒店+租车)。

方案四:本地消息表 / 事务消息(最终一致,最常用)

核心思路:**把「业务操作」和「发消息」放在同一个本地事务里**,保证两者原子性。然后异步投递消息,下游消费。

BEGIN;
  INSERT INTO orders (...) VALUES (...);
  INSERT INTO message_outbox (topic, payload, status) VALUES ('stock.deduct', ..., 'PENDING');
COMMIT;
-- 独立线程扫描 outbox,投递 MQ,成功后标记 SENT

优点:实现简单,不侵入业务代码;可靠性高(消息和业务同库同事务)。

缺点:需要额外的 outbox 表和投递线程;下游要保证幂等(消息可能重复)。

适用:绝大多数业务场景的默认选择。**如果只有一个方案可选,选这个。**

RocketMQ 的事务消息是这个思路的产品化实现,省掉了自己写 outbox 的功夫。

方案五:最大努力通知

最简单粗暴:发起方执行业务后,尽力通知下游,失败就定时重试(比如重试 5 次,间隔递增)。下游如果一直收不到,靠对账来兜底。

优点:实现成本极低,不需要 MQ,不需要事务框架。

缺点:不保证一定送达,必须有对账机制兜底。

适用:对实时性要求不高、能接受人工介入的场景,比如第三方支付回调、积分发放。

方案对比

方案 一致性 性能 改造成本 适用场景
2PC/XA 强 差 低 低并发内部系统
TCC 强 好 高 资金/库存核心链路
Saga 最终 好 中 长流程、多参与方
本地消息表 最终 好 低 大多数业务(推荐)
最大努力通知 最终 好 极低 非核心、可对账

三个实战经验

1. 能不分布式就不分布式。 最可靠的分布式事务方案是「不要分布式事务」。评估一下:这两个服务真的需要拆开吗?能不能合并?很多分布式一致性问题,本质是拆错了服务边界。

2. 优先选最终一致 + 对账。 银行转账也不需要毫秒级一致,T+0 对账就能兜住所有异常。设计时先问「这个业务能接受多长时间的中间态」,往往答案是「几分钟都行」,那就没必要上 TCC。

3. 幂等是前提,不是可选项。 所有最终一致方案都依赖消息重投或补偿重试,如果下游不幂等,重试就是灾难。**先做好幂等,再谈分布式事务。**

小结

选型的核心判断是三个问题:需要多强的一致性?并发量多大?能接受多大的改造成本?

实际项目里的典型组合:核心交易链路用 TCC(资金)+ 本地消息表(库存扣减通知)+ 每日对账兜底。其余非核心流程一律最终一致 + 最大努力通知。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。