微服务架构下,分布式事务没有银弹,核心解决方案包括两阶段提交(2PC)、TCC、Saga以及基于消息的最终一致性,选型必须根据业务场景对一致性、性能和成本的容忍度做权衡。参考2
分布式事务解决方案对比:2PC、TCC与Saga孰优孰劣
分布式事务的诞生源于单体应用拆分为微服务后,原本在一个数据库内完成的事务被迫跨多个独立资源,传统ACID无法直接适用,行业共识因此演化出几种主流方案,它们各有取舍。
两阶段提交:强一致性的代价
2PC是最早被尝试的方案,通过引入协调者将事务分为准备和提交两个阶段,所有参与者必须全部就绪才能提交,否则全部回滚,这种机制在一致性要求极高的场景(如跨行转账)中仍有应用,但代价非常明显:
- 同步阻塞:协调者等待所有参与者响应期间,资源被锁定,高并发下极易出现性能瓶颈。
- 单点风险:协调者一旦宕机,整个事务可能陷入僵局。
- 适用局限:多数现代中间件已经不再推荐,除非业务能接受较短的锁时间。
实际使用中,2PC更适合传统企业级应用,互联网场景几乎不会直接采用,但你可以通过分布式事务解决方案Seata的AT模式间接体验类似效果,它通过代理数据源做了优化。
TCC模式:业务补偿的艺术
TCC(Try-Confirm-Cancel)将事务拆分为三个阶段,由业务方自行实现预留、确认和回滚逻辑,Try阶段尝试锁定资源,Confirm阶段真正执行,Cancel阶段释放预留,这是一种非常灵活的设计,但要求开发人员对每个操作都编写对应的补偿逻辑。
优势在于性能高,锁完全由业务控制,不依赖数据库锁,劣势同样突出:开发成本高,Try、Confirm、Cancel三个接口必须幂等,且Cancel需要能处理中间状态,多数情况下,TCC适用于短事务、高并发且对一致性要求较高的场景,如扣减库存、账户扣款。
Saga模式:长事务的减负方案
Saga将一个长事务分解为多个本地事务,每个本地事务完成后立即提交,并通过补偿事务回滚,Saga有两种执行方式:编排(Choreography)和协调(Orchestration),编排依靠事件驱动,协调则由一个中心控制器管理。
Saga的最大优势是不持有锁,适合耗时较长的业务流程,如订单履约、旅游预订,但缺点也很明显它只提供最终一致性,且补偿逻辑的编写同样复杂,从实际反馈看,Saga在复杂业务中更受青睐,但需要事务管理平台支持断点恢复。参考2
| 方案 | 一致性 | 性能 | 开发成本 | 典型场景 |
|---|---|---|---|---|
| 2PC | 强一致 | 低 | 中 | 跨行转账、传统金融 |
| TCC | 强一致 | 高 | 高 | 短事务、高频扣款 |
| Saga | 最终一致 | 高 | 高 | 长事务、跨境订单 |
分布式事务解决方案Seata:国产开源组件如何落地
Seata是阿里开源的一套分布式事务解决方案,目前在国内社区热度极高,它支持AT、TCC、Saga和XA四种模式,其中AT模式最受欢迎,因为它对业务代码侵入性最低。
AT模式的核心机制
AT模式本质上是对2PC的优化,它通过代理JDBC数据源,自动解析SQL语句并记录回滚日志,在准备阶段,Seata会生成一条“镜像”记录到undo_log表;提交阶段则删除镜像;回滚阶段通过镜像数据恢复原状态。
实操步骤如下:
- 在每个微服务中引入
seata-spring-boot-starter依赖。 - 配置
application.yml,指定事务分组和注册中心地址(如Nacos)。 - 解压Seata Server并启动,默认端口8091。
- 在业务方法上添加
@GlobalTransactional注解,Seata会自动拦截请求并开启全局事务。
关键点:AT模式依赖数据库的本地事务,且undo_log表必须与业务表在同一数据库,Seata通过分支事务ID关联全局事务,一旦某个分支失败,所有分支都会被回滚。
使用Seata的注意事项
- 数据源必须使用Seata代理的
DataSourceProxy,否则回滚日志无法写入。 - 事务超时时间需要合理设置,默认60秒,超过后全局事务会自动回滚。
- 高并发场景下建议使用TCC或Saga模式,因为AT模式在准备阶段会持有行锁,性能瓶颈明显。
基于消息的最终一致性:分布式事务解决方案的轻量选择
当业务能够接受短暂的数据不一致时,基于消息的最终一致性是性价比最高的方案,它不需要引进额外的协调者,也不需要对业务代码做大幅改造,只需要利用消息队列的可靠投递和本地事务表。
本地消息表方案
这是最经典的实现方式,思路如下:
- 在业务服务中创建一张本地消息表,记录待发送的消息。
- 业务操作与消息写入在同一个本地事务中完成。
- 异步线程轮询本地消息表,将未发送的消息投递到MQ。
- 消费方收到消息后执行操作,并确认消费。
这套方案的最大优势是通用性强,任何MQ都能配合,劣势在于需要轮询,且消息表的维护增加了开发量,从实践中看,此方案适合订单状态同步、积分发放等场景。
RocketMQ事务消息
RocketMQ原生支持事务消息,将发送消息分为prepare和commit两步,prepare阶段消息对消费者不可见,commit后变为可见,如果commit失败,消息队列会回查生产者检查事务状态,从而决定commit或rollback。
操作步骤大致如下:
- 生产者实现
TransactionListener接口,定义executeLocalTransaction和checkLocalTransaction方法。 - 发送消息时调用
sendMessageInTransaction,传入消息体与业务参数。 - 在
executeLocalTransaction中执行本地业务,并返回COMMIT_MESSAGE或ROLLBACK_MESSAGE。 - 如果返回UNKNOWN,RocketMQ会定期回调
checkLocalTransaction确认状态。
优势:彻底解耦了业务和消息状态,无需轮询。不足:必须使用RocketMQ,且对业务的设计有一定要求,据统计,RocketMQ事务消息在电商场景中的应用非常广泛,尤其是支付成功后异步通知下游服务。
如何选择分布式事务解决方案:场景与成本考量
没有完美的方案,只有合适的组合,以下是一些选型路径,供参考。
高一致性+高频扣款:TCC是首选
如果你在做秒杀扣库存或者账户余额扣减,TCC的Try阶段预留资源能保证不超卖,性能也足够高,但需评估开发团队是否具备编写补偿逻辑的能力,如果团队较小,可以考虑Seata的TCC模式,框架帮你处理了部分重复工作。
长流程+可补偿:Saga更适合

机票预订、酒店支付这类业务,流程可能持续数分钟甚至数小时,不可能一直锁住资源,Saga的最终一致性刚好满足要求,可以选用Seata的Saga状态机,或者自己基于事件驱动实现。
低预算+简单集成:消息最终一致性最省心
如果业务对一致性要求不高,团队又不想引入额外框架,直接用RocketMQ事务消息或本地消息表,开发量可控,运维成本低。这是分布式事务解决方案中价格成本最低的选项,尤其适合中小型企业。
地域性考虑:开源方案与云服务对比
如果团队部署在简米云或酷番云,可以直接使用云厂商提供的分布式事务产品,如GTS(全局事务服务),但若涉及私有化部署或跨地域机房,Seata等开源方案更灵活。分布式事务解决方案 北京 上海 跨区域部署时,建议用Saga配合消息队列,避免2PC因网络延迟导致超时。
分布式事务没有放之四海而皆准的答案,2PC、TCC、Saga和消息最终一致性各自对应了不同的权衡点。关键是把一致性的要求从业务维度降下来,用最终一致性处理大部分场景,只在核心链路中采用强一致方案,技术选型应该服务于业务,而不是反过来。
分布式事务解决方案常见问题
分布式事务和普通事务有什么区别?
普通事务基于单个数据库的ACID,依靠锁和日志保证原子性,分布式事务跨越多个数据库或服务,无法简单地使用本地锁,因此需要通过协议或协调者来保证全局一致性,前者性能高但范围有限,后者扩展性强但需要牺牲部分性能或一致性。
TCC方案的幂等性如何保证?
TCC的每个阶段都可能被重试,幂等性必须在业务代码中实现,常见做法是在数据库表中增加唯一索引,或使用状态机确保同一操作只生效一次,例如在Confirm阶段,可以先用事务检查该记录是否已处理,若已处理则直接返回成功。
Seata的AT模式与TCC模式有何不同?
AT模式自动解析SQL并生成回滚日志,对业务代码侵扰极小,但会在准备阶段持有行锁,性能受限于数据库的锁竞争,TCC模式由业务方自己编写Try、Confirm、Cancel逻辑,锁的粒度更细,性能更高,但开发成本显著增加,且需要处理幂等和空回滚。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/530273.html


