type
status
date
slug
summary
tags
category
password

1、概述

分布式系统会把一个应用系统拆分为可独立部署的多个服务。服务之间通过远程通信来互相调用。服务内部依然可以通过本地事务来做事务控制,但服务之间的操作则无法再依赖本地事务来控制了,这就需要用到分布式事务。
具体一点而言,分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
notion image
上图中包含了库存和订单两个独立的微服务,每个微服务维护了自己的数据库。在交易系统的业务逻辑中,一个商品在下单之前需要先调用库存服务,进行扣除库存,再调用订单服务,创建订单记录。
notion image
可以看到,如果多个数据库之间的数据更新没有保证事务,将会导致出现子系统数据不一致,业务出现问题。

2、分布式事务方案

分布式事务的实现有许多种,下面介绍比较经典的方案:
  • XA规范
  • 2PC(二阶段提交)
  • 3PC(三阶段提交)
  • Saga
  • TCC
  • 本地消息表
  • 可靠事务消息
  • 最大努力通知

2.1 XA规范

XA 是由 X/Open 组织提出的分布式事务的规范,是后面的 Saga、TCC 的基础。XA 仅仅是个规范,具体的实现是数据库产商来提供的,目前主流的数据库基本都支持 XA 事务,包括 Mysql、Oracle、Sqlserver、Postgre 等,比如 Mysql 提供了 XA 规范的接口函数和类库实现。
XA 包含四个角色:
  • AP(Application Program)应用程序:就是要使用分布式事务的应用程序。
  • RM(Resource Manager)资源管理器:通常就是指数据库,要访问的资源在数据库中,然后数据库会保障资源的 ACID 特性。
  • TM(Transaction Manager)事务管理器:就是在系统里嵌入的一个专门管理横跨多个数据库事务的一个组件,主要是给事务分配唯一标识,负责事务的启动、提交及回滚,保障全局事务的原子性。
  • CRM(Communication Resource Manager)通信资源管理器:一般是由消息中间件来作为这个组件,也可以没有。
这里的 RM、TM、AP 三个角色是经典的角色划分,会贯穿后续 Saga、Tcc 等事务模式。
XA 事务由一个应用程序(AP)、一个或多个资源管理器(RM)、一个事务管理器(TM)组成。XA 协议中分为两阶段:
  1. 第一阶段(prepare):即所有的参与者(RM)准备执行事务并锁住需要的资源。参与者 ready 时,向 TM 报告已准备就绪。
  1. 第二阶段 (commit/rollback):当事务管理者(TM)确认所有参与者(RM)都 ready 后,向所有参与者发送 commit 命令。
notion image
如果有一阶段 prepare 操作失败,那么 TM 会通知各 RM 进行回滚,最后事务成功回滚。
notion image
优点:
  • 简单易理解
  • 开发较容易,回滚之类的操作,由底层数据库自动完成
缺点:
  • 对资源进行了长时间的锁定,并发度低,不适合高并发的业务

2.2 2PC(二阶段提交)

XA 其实都只是定义了一套规范,2PC(Two-Phase Commit)即两阶段提交协议则定义了实现分布式事务过程的细节。两阶段提交协议是将事务的提交过程分成了准备阶段提交阶段
  • 准备阶段:协调者询问所有参与者是否可以提交
  • 提交阶段:根据参与者反馈决定提交或中止
具体实现:
  1. 准备阶段。TM 会向参与此次事务的各个 RM 发起预提交事务的请求,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的 Redo 和 Undo 日志,但不提交。
    1. 事务询问:协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。
    2. 执行事务:参与者节点检查事务权限,执行询问发起为止的所有事务操作,并将 Undo 信息和 Redo 信息写入事务日志。
    3. 各参与者节点响应协调者节点发起的询问:如果参与者节点的事务操作实际执行成功,则它返回一个 Yes 消息;如果参与者节点的事务操作实际执行失败,则它返回一个 No 消息。
notion image
  1. 提交阶段。协调者根据各参与者的反馈情况来决定最终是否可以执行事务提交。有两种可能:
      • 执行事务提交。假如协调者从所有的参与者获得的反馈都是 Yes 响应,就会执行事务的提交。
          1. 发送提交请求。协调者向所有的参与发送 Commit 请求。
          1. 事务提交。参与者收到 Commit 请求后,会正式执行事务的 Commit 操作,并在完成提交后释放在整个事务期间内占用的资源。
          1. 反馈事务提交结果。参与者在完成事务提交后,向协调者发送 Ack 消息。
          1. 完成事务。协调者接收到所有参与者反馈的 Ack 消息后,完成事务。
      • 中断事务。如果任一参与者节点在第一阶段返回的响应消息为”No”,或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时,就会中断事务。
          1. 发送回滚请求。协调者向所有的参与发送 Rollback 请求。
          1. 事务回滚。参与者收到 Rollback 请求后,利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
          1. 反馈事务回滚结果。参与者在完成事务回滚后,向协调者发送 Ack 消息。
          1. 中断事务。协调者接收到所有参与者反馈的 Ack 消息后,完成事务中断。
      notion image
优点:
  • 实现强一致性,原理简单,实现方便
缺点:
  • 同步阻塞:在两阶段提交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,而且在准备阶段占用的资源,一直到分布式事务完成才会释放,这个过程中如果其他人要访问这个资源,也会被阻塞住。
  • 单点故障:TM 是个单点,一旦 TM 出现问题,那么整个两阶段提交流程将无法运转,更为严重的是,如果 TM 是在提交阶段出现问题的话,那么其他参与者将会一直处于锁定事务资源的状态中,而无法继续完成事务操作。
  • 数据不一致:在二阶段提交的阶段二中,当协调者向参与者发送 commit 请求之后,发生了局部网络异常或者在发送 commit 请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了 commit 请求。而在这部分参与者接到 commit 请求之后就会执行 commit 操作。但是其他部分未接到 commit 请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。

2.3 3PC(三阶段提交)

为了解决 2PC 的问题,提出了 2PC 的改进版即三阶段提交协议(3PC),主要改进点:
  • 引入了 CanCommit 阶段:将 2PC 的准备过程一分为二,在 CanCommit 阶段确认所有参与者的状态正常
  • 引入超时机制:在协调者和参与者中都引入超时机制,如果其中一方出现故障,仍能保证事务可以正常提交,不会长时间阻塞系统。
3PC 由 CanCommitPreCommitDoCommit 三个阶段组成。
  • CanCommit阶段(询问阶段):协调者询问所有参与者的状态(网络环境、是否可提交事务)
  • PreCommit阶段(预提交阶段):协调者询问所有参与者是否可以预提交
  • DoCommit阶段 (提交阶段):根据参与者反馈决定最终提交或中止
具体实现:
  1. CanCommit 阶段:TM 首先发一个 CanCommit 消息给参与事务的 RM,这一步不会执行实际的SQL,其实就是看能否访问通 RM,包括 RM 自身的一些网络环境等,如果连某一个 RM 都访问不通,就没必要继续执行事务了。
    1. 事务询问:协调者向参与者发送 CanCommit 请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
    2. 响应反馈:参与者接到 CanCommit 请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回 Yes 响应,并进入预备状态。否则反馈 No。
    3. notion image
  1. PreCommit 阶段:阶段二类似于 2PC 的准备阶段。协调者会根据第一阶段的询盘结果采取相应操作,一般也有两种情况:
      • 执行事务预提交:假如协调者从所有的参与者获得的反馈都是 Yes 响应,那么就会执行事务的预提交。
          1. 发送预提交请求:协调者向参与者发送 PreCommit 请求,并进入 Prepared 阶段。
          1. 事务预提交:参与者接收到 PreCommit 请求后,会执行事务操作,并将 Undo 和 Redo 信息记录到事务日志中。
          1. 响应反馈:如果参与者成功的执行了事务操作,则返回 ACK 响应,同时开始等待最终指令:提交(commit)或中止(abort)。
      • 中断事务:假如有任何一个参与者向协调者发送了 No 响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
          1. 发送中断请求:协调者向所有参与者发送 abort 请求。
          1. 中断事务:参与者收到来自协调者的 abort 请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
      notion image
  1. DoCommit 阶段:阶段三类似于 2PC 的提交阶段,会进行真正的事务提交。也会存在两种可能:
      • 执行事务提交。假如协调者从所有的参与者获得的反馈都是 ACK 响应,就会执行事务的提交。
          1. 发送提交请求:协调者向所有参与者发送事务 commit 通知
          1. 事务提交:所有参与者在收到通知之后执行 commit 操作,并释放占有的资源
          1. 反馈事务提交结果:参与者在完成事务提交后,向协调者发送 Ack 消息。
          1. 完成事务。协调者接收到所有参与者反馈的 Ack 消息后,完成事务。
      • 中断事务:假如协调者接收到任意一个参与者返回了 No 响应,或者在等待超时后没有接收到所有参与者的反馈响应,那么就会执行中断事务。
          1. 发送回滚请求。协调者向所有的参与发送 Rollback 请求。
          1. 事务回滚。参与者收到 Rollback 请求后,利用之前写入的 Undo 信息执行回滚,并释放在整个事务期间内占用的资源。
          1. 反馈事务回滚结果。参与者在完成事务回滚后,向协调者发送 Ack 消息。
          1. 中断事务。协调者接收到所有参与者反馈的 Ack 消息后,完成事务中断。
      notion image
3PC 相比于 2PC 的改进:主要解决了单点故障问题和同步阻塞问题(但没有解决数据不一致问题)。
  • 引入了 CanCommit 阶段,这一步首先确认所有 RM 的环境都是OK的。
  • RM 在 DoCommit 阶段等待超时就会自动提交事务。在 DoCommit 阶段,如果 RM 收到 PreComit 消息并返回成功了,但是等待超时没有收到 TM 发来的 DoCommit 或 abort 消息,RM 就会判定 TM 故障了。RM 会认为,既然接收到了 PreCommit 消息,说明 CanCommit 阶段所有的 RM 一定是返回成功的,所以如果超时没有收到 DoCommit 消息,RM 就会认为其它 RM 的 PreCommit 都会成功,然后都可以自动执行事务提交。
优点:
  • RM 可以自己提交事务,解决 TM 单点故障的问题
缺点:
  • 数据不一致:在 DoCommit 阶段,如果 TM 发送 abort 消息给一部分 RM 后挂了,这部分 RM 回滚事务,然后其余的 RM 等待超时自动提交了事务,这就会造成数据不一致的问题。

2.4 Saga

Saga 是一种管理长时间运行的分布式事务的方案,其核心思想是通过将一个大事务拆分为一系列本地小事务,并配合补偿机制来保证最终一致性。具体实现:
  1. 拆分事务:将一个大事务分解为多个本地小事务(Saga 子事务)
  1. 补偿机制:为每个子事务设计对应的补偿操作(回滚操作)
  1. 执行协调:由 Saga 事务协调器协调,按照一定顺序执行子事务,失败时执行反向补偿
我们的全局事务发起人,将整个全局事务的编排信息,包括每个步骤的正向操作和反向补偿操作定义好之后,提交给服务器,服务器就会按步骤执行前面 Saga 的逻辑。可以看到,和 TCC 相比,Saga 没有“预留”动作,它的本地小事务就是直接提交到库。
例如我们要进行一个类似于银行跨行转账的业务,将 A 中的 30 元转给B,根据 Saga 事务的原理,我们将整个全局事务,切分为以下服务:
  • 转出(TransOut)服务,这里转出将会进行操作A-30
  • 转出补偿(TransOutCompensate)服务,回滚上面的转出操作,即 A+30
  • 转入(TransIn)服务,转入将会进行 B+30
  • 转入补偿(TransInCompensate)服务,回滚上面的转入操作,即 B-30
整个 SAGA 事务执行成功的逻辑是:
notion image
如果在中间发生错误,例如转入B发生错误,则会调用已执行分支的补偿操作,即:
notion image
当 SAGA 对分支 A 进行失败补偿时,A 的正向操作可能
  1. 已执行;
  1. 未执行;
  1. 甚至有可能处于执行中,最终执行成功或者失败是未知的。
SAGA 在对 A 进行补偿时,要妥善处理好这三种情况。
优点:
  • 并发度高,不用像 XA 事务那样长期锁定资源。
缺点:
  • 需要定义正常操作以及补偿操作,开发量比 XA 大
  • 一致性较弱,例如业务是发送短信,补偿动作则得再发送一次短信说明撤销,用户体验比较差。
  • 不能保证隔离性,需要在业务自行控制并发
适用场景:
  • SAGA 适用的场景较多,长事务适用,对中间结果不敏感的业务场景适用

2.5 TCC

TCC(Try-Confirm-Cancel)的概念,是基于 2PC 提出的。TCC 分为 3 个阶段
  • Try 阶段(预留资源):检查并锁定所需资源(例如冻结部分资金、预占库存),但不直接提交事务。
  • Confirm 阶段(确认执行):如果所有参与者的 Try 都成功,使用 Try 阶段预留的业务资源提交事务。需要保证幂等性(重复调用不产生副作用)。
    • notion image
  • Cancel 阶段(补偿回滚):任一参与者的 Try 失败,释放 Try 阶段预留的业务资源。同样需要幂等性。
    • notion image
优点:
  • 实现很灵活,几乎可以满足任何分布式事务的场景
  • 并发度较高,无长期资源锁定。
  • 一致性较好,不会发生 Saga 已扣款最后又转账失败的情况
缺点:
  • 开发量较大,需要开发 Try/Confirm/Cancel 三个接口,且需要考虑幂等性。
  • 其实实现思想还是依据 2PC,因此包含了 2PC 所有缺点。
适用场景:
  • TCC 主要用于处理一致性要求较高、需要较多灵活性的短事务。
假如 Confirm/Cancel 阶段失败会怎么样
按照 TCC 模式的协议,Confirm/Cancel 操作是要求最终成功的,遇见失败的情况,都是由于临时故障或者程序 bug。DTM 在 Confirm/Cancel 操作遇见失败时,会不断进行重试,直到成功。
为了避免程序 bug 导致补偿操作一直无法成功,建议开发者对全局事务表进行监控,发现重试超过 3 次的事务,发出报警,由运维人员找开发手动处理。
TCC如何做到更好的一致性
对于我们的 A 跨行转账给 B 的场景,如果采用 Saga,在正向操作中调余额,在补偿操作中,反向调整余额,那么会出现这种情况:如果 A 扣款成功,金额转入 B 失败,最后回滚,把 A 的余额调整为初始值。整个过程中如果 A 发现自己的余额被扣减了,但是收款方 B 迟迟没有收到资金,那么会对 A 造成非常大的困扰。
上述需求在 SAGA 中无法解决,但是可以通过 TCC 来解决,设计技巧如下:
  • 在账户中的 balance 字段之外,再引入一个 trading_balance 字段
  • Try 阶段检查账户是否被冻结,检查账户余额是否充足,没问题后,调整 trading_balance(即业务上的冻结资金)
  • Confirm 阶段,调整 balance ,调整 trading_balance(即业务上的解冻资金)
  • Cancel 阶段,调整 trading_balance(即业务上的解冻资金)
这种情况下,终端用户 A 就不会看到自己的余额扣减了,但是 B 又迟迟收不到资金的情况
为什么只适合短事务
TCC 的事务编排放在了应用端上,就是事务一共包含多少个分支,每个分支的顺序什么样,这些信息不会像 Saga 那样,都发送给 DTM 服务器之后,再去调用实际的事务分支。当应用出现 crash 或退出,编排信息丢失,那么整个全局事务,就没有办法往前重试,只能够进行回滚。如果全局事务持续时间很长,例如一分钟以上,那么当应用进行正常的发布升级时,也会导致全局事务回滚,影响业务。因此 TCC 会更适合短事务。
那么是否可以把 TCC 的事务编排都保存到服务器,保证应用重启也不受到影响呢?理论上这种做法是可以解决这个问题的,但是存储到服务器会比在应用端更不灵活,无法获取到每个分支的中间结果,无法做嵌套等等。
考虑到一致性要求较高和短事务是高度相关的(一个中间不一致状态持续很长时间的事务,自然不能算一致性较好),这两者跟“应用灵活编排”,也是有较高相关度,所以将 TCC 实现为应用端编排,而 Saga 实现为服务端编排。

2.6 本地消息表

本地消息表的核心思想是将分布式事务拆分成多个本地事务进行处理。事务主动发起方首先在本地新建事务消息表,如下所示:
工作过程:
  1. 消息存储:事务发起方将业务处理事务消息存入事务消息表放在同一个本地事务中完成。
  1. 消息轮询:通过定时任务轮询本地消息表,将待处理的事务消息通过消息队列(推荐)或 HTTP 调用发送给其他服务。
  1. 状态更新:消息发送成功后更新消息状态。
  1. 重试机制:对于发送失败的消息进行重试。
notion image
不同于 TCC 提供了 Cancel 取消接口,本地消息表则不提供回退的补偿机制。如果服务方向下游服务发送事务消息失败,会一直重试,直到成功为止,一直不成功则人工处理。所以本地消息表其实就是利用了系统的本地事务来实现的一种最终一致性的分布式事务方案。
优点:
  • 长事务仅需要分拆成多个任务,使用简单
  • 不会长时间锁住资源,减少死锁风险
  • 没有长事务,执行效率高,提高吞吐量
缺点:
  • 生产者需要额外的创建消息表,每个本地消息表都需要进行轮询
  • 事务不是强一致性,而是最终一致性
  • 不支持回滚
适用场景:
  • 适用于可异步执行的业务,且后续操作无需回滚的业务

2.7 RocketMQ事务消息

在上述的本地消息表方案中,生产者需要额外创建消息表,还需要对本地消息表进行轮询,业务负担较重。阿里开源的 RocketMQ 4.3之后的版本正式支持事务消息。RocketMQ 事务消息的本质是把本地消息表放到 RocketMQ上,在发送消息的同时执行本地事务,其他方面的协议基本与本地消息表一致。
RocketMQ 事务消息采用二阶段提交机制:
  1. 发送半消息(Half Message):生产者发送"半消息"到 Broker,此时消息对消费者不可见
  1. 执行本地事务:生产者执行与消息相关的本地事务
  1. 提交或回滚事务:根据本地事务执行结果,生产者向 Broker 发送二次确认(Commit 或 Rollback)
      • 如果本地事务执行成功,提交 Commit,消息对消费者可见
      • 如果本地事务执行失败,提交 Rollback,消息将被丢弃
  1. 事务状态回查:如果生产者没有发送二次确认,Broker 会定期回查事务状态。常见事务消息状态:
    1. COMMIT_MESSAGE:提交事务,消息对消费者可见
    2. ROLLBACK_MESSAGE:回滚事务,消息将被丢弃
    3. UNKNOW:未知状态,需要后续回查
notion image
RocketMQ 事务消息使用示例:
1、生产者代码
2、消费者代码
RocketMQ 事务消息方案与本地消息表机制非常类似,区别主要在于原先相关的本地表操作替换成了一个反查接口。
优点:
  • 长事务仅需要分拆成多个任务,并提供一个反查接口,使用简单
缺点:
  • 事务消息的回查没有好的方案,极端情况可能出现数据错误
  • 不支持回滚
适用场景:
  • 适用于可异步执行的业务,且后续操作无需回滚的业务

2.8 最大努力通知

最大努力通知会尽最大努力将通知发送给接收方,但是不保证接收方一定收到消息。最大努力通知更偏向于设计理念,在具体实现上有多种实现方式。
最大努力通知的实现依赖于以下两个核心机制:
  • 消息重复通知机制:当接收方未成功接收通知时,通知方会按照预定义的策略(如时间衰减,间隔 1min、5min、10min、30min、1h、2h、5h、10h)进行多次重试,直到达到最大重试次数,可记录错误日志或者告警让人工介入处理。
  • 消息校对机制:如果通知最终未成功,接收方可以主动调用发起方的查询接口校对业务结果。
具体实现方案:
方案1:基于 MQ 的 ACK 机制(内部系统适用)
适用于业务发起方和接收方在同一个内部系统,共享同一 MQ 服务的情况:
  1. 消息发送:业务发起方将通知消息发送至 MQ(普通消息)。
  1. 消息监听:接收方监听 MQ 并消费消息。
  1. ACK 确认
      • 接收方处理成功后返回 ACK,MQ 停止重试。
      • 若未返回 ACK,MQ 按递增时间间隔(如1min、5min、10min、30min、1h、2h、5h、10h)重复投递,直到达到最大重试次数或超时窗口。
  1. 校对机制:接收方可调用发起方的查询接口校对消息一致性。
方案2:基于通知服务(外部系统适用)
适用于跨企业或跨网络的场景(如支付宝、微信支付回调):
  1. 消息发送:业务发起方使用事务消息确保本地事务与 MQ 消息的原子性,发送至 MQ。
  1. 通知服务监听
      • 独立的通知服务(而非接收方直接监听 MQ)消费 MQ 消息。
      • 若通知服务未返回 ACK,MQ 会重复投递。
  1. 外部调用:通知服务通过 HTTP 等协议调用接收方的回调接口。
  1. 校对机制:接收方可主动查询业务结果。
关键技术点:
  • 幂等性:接收方的回调接口和发起方的查询接口必须支持幂等,避免重复处理。
  • 重试策略
    • 采用时间衰减策略(如逐步拉大重试间隔)。
    • 最大重试次数可配置(如 RocketMQ 默认 16 次)。

2.9 AT事务模式

AT(Automatic Transaction)事务模式是阿里开源项目 seata 中的一种事务模式,是 seata 主推的事务模式,在蚂蚁金服也被称为 FMT。AT 从原理上面看,与 XA 的设计有很多相近之处:XA 是数据库层面实现的二阶段提交, AT 则是应用/驱动层实现的二阶段提交
AT 模式的特点:
  • 非侵入性:对业务代码几乎无侵入,开发者可以像使用本地事务一样使用分布式事务
  • 自动补偿:通过自动生成回滚日志(Undo Log)实现事务回滚
  • 高性能:二阶段提交异步化,非常快速地完成
  • 适用性广:基于支持事务的关系型数据库,适用于高性能、高并发的微服务架构
AT 的角色(类似于 XA):
  • RM 资源管理器:是业务服务,负责本地数据库的管理,与 XA 中的 RM 一致
  • TC 事务协调器:是 Seata 服务器,负责全局事务的状态管理,负责协调各个事务分支的执行,相当于 XA 中的 TM
  • TM 事务管理器:是业务服务,负责全局事务的发起,相当于 XA 中的 APP
AT 模式的二阶段提交:
  1. 第一阶段:业务执行与本地提交
    1. 开启事务:RM 侧用户开启本地事务
    2. SQL解析:解析业务 SQL,得到 SQL 类型(UPDATE/INSERT/DELETE)、表、条件等信息
    3. 查询前镜像(Before Image):根据解析的 SQL 条件,查询出修改前的数据状态
    4. 执行业务SQL:执行实际的业务 SQL 操作
    5. 查询后镜像(After Image):根据主键查询出修改后的数据状态
    6. 插入回滚日志:将前后镜像数据及业务 SQL 信息组成回滚日志记录,插入到 UNDO_LOG 表中
    7. 注册分支事务:向 TC 注册分支事务,申请相关记录的全局锁
    8. 本地事务提交:业务数据的更新和 UNDO LOG 一并提交
  1. 第二阶段:全局提交或回滚
    1. 如果 AT 的第一阶段所有 RM 都没有错误,进行 COMMIT 操作
      1. TC 删除全局事务相关的所有 lockKey(全局锁)。
      2. TC 通知与当前这个全局事务相关的所有业务服务,告知全局事务已成功,可以删除 UNDO_LOG 数据。
      3. RM 收到通知后异步删除 UNDO_LOG 记录。
    2. 如果 AT 的第一阶段有 RM 出错,进行 ROLLBACK 操作
      1. TC 通知相关业务服务执行回滚
      2. RM 从 UNDO_LOG 中取出 BeforeImage 和 AfterImage。
      3. 校验 AfterImage 与当前数据库数据是否一致
      4. 如果一致,使用 BeforeImage 执行回滚操作
      5. 如果不一致(发生脏回滚),需要人工介入处理
      6. 回滚完成后删除 UNDO_LOG 记录
AT模式使用示例
1、在 Spring Boot 项目中引入 Seata 依赖:
2、配置数据源代理
3、创建 UNDO_LOG 表
4、开启分布式全局事务
AT 模式的缺点:
  1. 脏读问题:默认全局隔离级别是读未提交,可能读到中间状态数据
  1. 脏回滚风险:当其他事务修改了已被 AT 事务修改的数据时,可能导致回滚失败需要人工介入
  1. 数据库支持限制:需要支持本地 ACID 事务的关系型数据库
  1. 性能开销
      • 需要额外执行 SQL 查询前后镜像。相比 XA 模式,AT 模式下 RM 侧执行的SQL数量更多(3 writes,2 read vs XA 的 1 update)
      • 需要额外维护 UNDO_LOG 表

2.10 适用场景总结

方案
一致性
性能
复杂度
适用场景
不适用场景
典型案例
XA/2PC/3PC
强一致
强一致性需求:如金融交易、支付系统等要求严格数据一致的场景。 传统数据库协作:单系统跨多个关系型数据库(如MySQL、Oracle)的分布式事务。
高并发或长事务(性能差,协调者单点问题)。 跨异构系统(如数据库+消息队列)。
银行跨行转账
TCC
最终一致
高并发 & 最终一致:电商、秒杀系统等需要高并发的业务。 异构系统整合:跨数据库、消息队列、缓存等不同中间件。 短事务:业务逻辑可分阶段执行(如预订、支付、确认流程),每个阶段的事务执行时间段。
无法拆分 Try/Confirm/Cancel 的业务(如实时性极强的操作)。 开发成本高(需手动实现补偿逻辑)。
订单创建(Try锁库存 → Confirm扣款 → Cancel释放库存)。
SAGA
最终一致
长事务:跨多个服务的业务流(如旅行订票:酒店+航班+租车)。 遗留系统改造:无法实现 TCC 的原子性时,通过补偿机制实现最终一致。
需强一致性的场景(补偿可能失败)。 补偿逻辑复杂的业务。
微服务架构中的跨服务订单流程(如Uber订车后取消需退款)。
本地消息表
最终一致
简单分布式事务:如订单状态同步、物流状态更新、发短信、积分变更。 异构系统整合:跨数据库、消息队列、缓存等不同中间件。 高可靠要求:通过本地事务保证消息必达。
需同步返回结果的场景。
电商订单支付成功后,异步通知物流系统发货。
RocketMQ事务队列
最终一致
高吞吐场景:高并发系统,对事务的性能要求高。 异构系统整合:跨数据库、消息队列、缓存等不同中间件。 高可靠要求:通过事务消息回查保证消息必达。
需同步返回结果的场景。
支付宝支付成功后,通过消息队列通知各业务系统。
最大努力通知
不保证
非核心业务:对最终一致性时间敏感度低的非核心业务,例如微信交易的结果,就是通过最大努力通知方式通知各个商户,既有回调通知,也有交易查询接口。
要求最终一致性的场景。
1、支付结果通知 2、订单支付成功后通知积分系统增加积分。 3、用户注册成功后通知推荐系统。 4、退款完成后通知财务系统。
Seata AT
最终一致
低侵入性:对业务代码侵入低(自动回滚)。 基于关系型数据库:系统使用 Mysql、Oracle 等传统关系型数据库。 简单分布式事务:适合单块应用拆分为微服务的过渡阶段。 云原生环境:与Kubernetes、Dubbo等集成。
非关系型数据库(如MongoDB)。 高频短事务(性能开销较高)。
微服务架构下的订单-库存-账户数据一致性。
技术选型:
  • 强一致:优先 2PC/3PC/XA(牺牲性能)。
  • 高并发&最终一致:TCC 或 RocketMQ 事务消息。
  • 长事务:SAGA。
  • 低侵入性:Seata AT 或本地消息表。

3、分布式事务框架

  • Seata (阿里巴巴开源):支持多种事务模式,例如AT、TCC、SAGA 和 XA
  • DTF (阿里云分布式事务服务):基于 Seata 扩展的云服务版本,提供可视化控制台和丰富的监控指标
  • Hmily (京东金融开源):轻量级 TCC 分布式事务框架,支持 Spring Cloud 和 Dubbo 集成
  • ByteTCC (字节跳动开源):基于T CC 模式的实现,支持 Spring Cloud 环境
  • JTA + Atomiko:XA 常用的技术框架
分布式一致性算法:Paxos算法Mysql锁篇:死锁问题
Loading...