分布式事务五种方案选型,别再傻傻只用Seata
在微服务架构盛行的今天跨服务的数据一致性几乎成了每个后端团队绕不开的难题。订单创建要扣库存、支付成功要发积分、转账要同时更新两个账户——这些操作跨越了多个数据库节点单机事务的 Transactional 彻底失效。很多人的第一反应是“上 Seata”但实际上分布式事务远不止 Seata 一种解法。本文梳理五种主流方案的核心原理与适用场景帮你建立清晰的选型思路。方案一2PC——强一致的代价两阶段提交是最经典的分布式事务协议。协调者先向所有参与者发送“准备”请求参与者执行本地事务但不提交仅反馈能否成功待全部参与者确认后协调者再统一发送“提交”或“回滚”指令。它的优势是强一致性实现上对业务代码几乎零侵入MySQL 等主流数据库原生支持 XA 协议。但问题同样突出同步阻塞。在 Prepare 阶段所有参与者持有的锁直到第二阶段才会释放。有团队在生产环境实测高峰期锁持有时间达到 500ms而业务操作本身仅 10ms响应时间直接飙到几秒。此外协调者单点故障和网络分区下的脑裂风险也始终存在。2PC 适合短事务、低并发的老系统跨库场景不适合高并发互联网业务。方案二TCC——把控制权还给业务TCC 将事务拆解为 Try、Confirm、Cancel 三个阶段。以转账为例Try 阶段先冻结转出方的 100 元Confirm 阶段完成实际转账Cancel 阶段解冻金额。一致性由业务代码主动控制性能远优于 2PC。但 TCC 的业务侵入性极高——每个接口都要实现三套逻辑。更麻烦的是三个经典陷阱空回滚Try 超时后 Cancel 先执行但 Try 实际成功了、悬挂Cancel 执行后 Try 才到达、幂等Confirm/Cancel 可能被重复调用。解决空回滚需要在 Cancel 前查询事务记录表确认 Try 是否执行过解决悬挂则要在 Try 执行前检查是否已有回滚标记。TCC 适合资金、库存扣减等对一致性要求高且业务逻辑可控的核心链路。方案三Saga——长流程的异步解耦Saga 将一个长事务拆分为多个本地短事务每个步骤都提交本地事务一旦某步失败则按反向顺序调用补偿操作。相比 TCCSaga 没有资源锁定性能更好适合订单履约、物流调度这类参与者多、流程长的场景。代价是隔离性缺失和补偿风暴风险。由于每一步都直接提交中间状态对外可见用户可能看到“订单已创建但库存尚未扣减”的短暂状态。如果补偿链条上的某个操作失败可能引发连锁补偿。Saga 适合业务容忍中间态、补偿逻辑清晰的长流程不适合需要强隔离的场景。方案四本地消息表——最简单可靠的最终一致核心思路是将分布式事务拆分为“本地事务 异步消息”。上游在同一个本地事务中写入业务数据和一条消息记录然后由定时任务扫描消息表投递到 MQ下游消费后执行本地操作。可靠性由本地数据库事务保证不依赖任何分布式协调器。本地消息表的实现简单、不侵入业务是业界使用最多的最终一致方案之一源于 eBay 的经典实践。缺点是需要维护消息表消息延迟不可控且下游必须做幂等处理。适合对实时一致性要求不高、以最终一致为目标的场景如下单后发积分、物流派单等。方案五MQ 事务消息——本地消息表的“托管版”RocketMQ 的事务消息本质上是对本地消息表的封装将消息表“搬”进了消息队列内部。生产者先发送一条对消费者不可见的半消息然后执行本地事务成功则提交半消息失败则回滚若确认丢失Broker 会主动回查生产者的事务状态。MQ 事务消息的吞吐量优于本地消息表消息数据独立存储降低了业务系统与消息系统的耦合。但强依赖特定 MQRocketMQ 支持较好Kafka 的事务机制语义不同通用性不如本地消息表。适合已使用 RocketMQ 且追求高吞吐的最终一致场景。选型决策从业务需求倒推技术方案与其先选技术再套业务不如从三个问题出发第一业务能接受多长的不一致窗口如果答案是“不能有任何不一致”TCC 是唯一选择如果能接受秒级甚至分钟级的延迟Saga、本地消息表和 MQ 事务消息都在考虑范围内2PC 则仅推荐用于遗留系统的短事务跨库操作。第二业务链路有多长涉及 2-3 个服务的短链路TCC 或消息方案更合适涉及 5 个以上参与者的长流程Saga 的编排能力更有优势。第三团队愿意承受多少业务侵入如果团队对补偿逻辑缺乏经验贸然上 TCC 可能引入比循环依赖更隐蔽的 bug。此时 Seata AT 模式值得考虑——它通过自动生成反向 SQL 实现回滚业务零侵入但需接受全局锁带来的性能损耗适合低并发场景。写在最后分布式事务没有银弹。Seata 只是提供了 AT、TCC、Saga、XA 四种模式的统一框架它解决的是“怎么实现”的问题而不是“该不该用”的问题。真正的选型能力在于准确判断业务对一致性的容忍边界然后在性能、复杂度和可靠性之间找到那个平衡点。能最终一致就别强一致能用消息解耦就别上 TCC——这才是落地的关键。