分布式事务方案对比

先明确一个核心前提

分布式事务要解决的是:一个业务操作跨了多个数据库或服务,如何保证数据一致性?

解决方案分为两大阵营:

  • 刚性事务(强一致性):Seata 的 AT、TCC、XA 模式。追求数据实时一致,所有服务要么一起成功,要么一起失败。

  • 柔性事务(最终一致性):本地消息表、MQ 事务消息。允许短暂不一致,通过重试保证数据最终一定对齐。

本地消息表

核心思想 :在本地业务数据库里建一张 outbox 表,把"写业务数据"和"写待发送消息"放在同一个本地事务里。业务成功后,用一个定时任务去扫 outbox 表,把消息发给 MQ,发送成功后再删除或标记这条消息。

特点:

  • 优点:实现简单,不依赖特殊 MQ,和业务代码耦合低。

  • 缺点:需要自己写定时任务和异常处理;消息可能重复发送,消费者必须幂等;有延迟,定时任务扫描间隔决定了消息的延迟时间。

适用场景:公司没有 RocketMQ 这类支持事务消息的 MQ,只能用 RabbitMQ 或 Kafka,但又需要保证消息一定发出去。

MQ 事务消息

核心思想:利用 RocketMQ 原生的事务消息机制,把"发送消息"和"执行本地事务"绑定在一起。先发半消息(消费者不可见),再执行本地事务,根据本地事务结果决定半消息是提交(消费者可见)还是回滚(丢弃)。

特点:

  • 优点:消息延迟低(实时性远高于本地消息表),不需要自己写定时任务和 outbox 表,RocketMQ 自带回查机制保证最终一致性。

  • 缺点:必须用 RocketMQ(RabbitMQ 和 Kafka 原生不支持);消费者必须幂等。

适用场景:公司有 RocketMQ,且对数据一致性的实时性要求高------比如下单后要立刻扣库存,不能等几秒后才发消息。

Seata AT 模式

核心思想:Seata 介入你的 SQL 执行过程,在事务提交前自动记录回滚日志(undo_log 表)。如果需要回滚,Seata 根据 undo_log 自动生成反向 SQL,把数据恢复原状。你的代码不需要写任何回滚逻辑。

特点:

  • 优点 :对业务代码零侵入(只需一个 @GlobalTransactional 注解),自动生成回滚日志,自动回滚。

  • 缺点 :依赖 Seata Server(需要额外部署);性能损耗比本地事务高;不支持 Redis、MongoDB 等非关系型数据库;不支持 SELECT ... FOR UPDATE 这类显式加锁的 SQL。

适用场景:Java 微服务项目,数据库全部是 MySQL(或其他关系型数据库),不想侵入业务代码,想用注解自动管理分布式事务。

Seata TCC 模式

核心思想:TCC 把每个服务需要做的事情拆成三步:Try(锁定资源)、Confirm(正式执行)、Cancel(释放资源)。所有 Try 都成功后,统一 Confirm;任何一个 Try 失败,统一 Cancel。这是业务层面的补偿,不是数据库层面的回滚。

特点:

  • 优点:性能更高(没有全局行锁),支持非数据库资源(Redis、文件系统等),业务可控性强。

  • 缺点:代码侵入性极高,每个接口都需要实现 Try、Confirm、Cancel 三个方法;开发工作量大,容易出错。

适用场景:对性能要求极高的场景(比如秒杀扣库存),或者涉及非数据库资源(需要同时操作 Redis 和 MySQL),或者公司已经有 TCC 框架沉淀。

Seata XA 模式

核心思想:利用数据库自身的 XA 协议(两阶段提交)。Seata 不在 SQL 层面做拦截,而是把分布式事务完全交给数据库去管理。第一阶段各数据库执行 SQL 但不提交(Prepare),第二阶段 Seata 通知所有数据库统一提交或回滚(Commit/Rollback)。

特点:

  • 优点:对业务代码几乎零侵入;强一致性,数据绝不脏读。

  • 缺点:性能最差(全局锁持有时间长,并发吞吐量断崖式下降);依赖数据库支持 XA 协议(MySQL 5.7+ 支持);不支持 Redis 等非数据库资源。

适用场景:对数据一致性要求极高(比如金融、会计系统),但对性能要求不高,且所有资源都是支持 XA 协议的关系型数据库。在实际生产中很少使用,因为性能代价太大。

Seata Saga 模式

核心思想是把一个长事务拆成多个短事务,每个短事务都有自己的补偿操作。如果某个步骤失败,不再回滚已经成功的步骤,而是按顺序反向执行补偿操作。

其优点 是不依赖全局锁和 undo_log,适合长事务(如需要人工审核的订单流程);缺点是必须为每个正向操作编写反向补偿逻辑。

这种方式适用场景是业务流程长、需要人工干预或调用外部系统(如银行接口)。

总结

没有银弹。刚性事务(AT、TCC、XA)追求强一致性,但各有代价;柔性事务(本地消息表、MQ 事务消息)允许短暂不一致,但通过重试保证最终对齐。架构设计的本质是权衡------你在选择方案的同时,也是在选择你愿意为数据一致性付出多大的性能代价。

相关推荐
逐流人3 小时前
Ceph分布式存储集群配置与池管理:从配置优先级到PG、复本池与纠删码池
运维·分布式·ceph·云原生·云计算·rados
天天喝旺仔6 小时前
gRPC 底层原理:HTTP/2 多路复用、Protobuf 序列化与四种流模式
分布式·http·微服务·rpc
灯澜忆梦9 小时前
【RabbitMQ #5】 | 三大交换机 Fanout ,Direct ,Topic
分布式·rabbitmq·ruby
.冰块.11 小时前
Ceph 分布式存储实战(二):存储池管理与 cephx 认证授权
分布式·ceph·rados·纠删码·复本池·cephx认证与用户权限
我们从未走散13 小时前
从内存字典到租约内核:分布式上游账号池如何做到不超卖
分布式
.冰块.14 小时前
Ceph 分布式存储实战(一):架构入门与 cephadm 集群部署
分布式·ceph·架构·cephadm
j7~15 小时前
【Redis】《一文走完服务端高并发架构演进:从单机架构到 K8S 容器编排》
分布式·架构演进·服务端高并发分布式结构演进之路·架构基本概念·架构评价指标
Flynt15 小时前
把 bug tracker 塞进 git 仓库,同步和冲突怎么解决?我把 git-bug 拆开实测了一遍
分布式·git·开源
灯澜忆梦1 天前
【RabbitMQ #3】 | Go 客户端 + SpringAMQP
分布式·golang·rabbitmq