Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
      Seata 有3个主要角色:事务管理器(TM,Transaction Manager)、资源管理器(RM,Resource Manager)和事务协调者(TC,Transaction Coordiator)。

  • TM:与 TC 交互,开启、提交、回滚全局事务。
  • RM:与 TC 交互,负责资源的相关处理,包括分支事务注册与分支事务状态上报。
  • TC:维护全局事务和分支事务的状态,推进事务两阶段处理。对于 AT 模式的分支事务,TM 负责事务并发控制。

      TM 和 RM 是以 SDK 的形式作为 Seata 的客户端与业务系统集成在一起的,TC 作为 Seata 的服务端独立部署。
请输入图片描述

      Seata 处理分布式事务的主要流程如下所示:

  1. TM 开启全局事务(TM 向 TC 开启全局事务);
  2. 事务参与者通过 RM 与资源交互,并注册分支事务(RM 向 TC 注册分支事务);
  3. 事务参与者在完成资源操作后,上报分支事务状态(RM 向 TC 上报分支事务完成状态);
  4. TM 结束全局事务,事务一阶段结束(TM 向 TC 提交/回滚全局事务);
  5. TC 推进事务二阶段操作(TC 向 RM 发起二阶段提交/回滚)。

请输入图片描述

Seata 事务模式

      Seata 支持4种事务模式:ATTCCSagaXA

AT模式

      AT模式是 Seata 主推的分布式事务解决方案,对业务无侵入,真正做到了业务与事务分离,用户只需关注自己的业务SQL。AT模式使用起来非常简单,与完全没有使用分布式事务方案相比,业务逻辑不需要修改,只需要增加一个事务注解@GlobalTransactional即可。

@Override
@GlobalTransactional
public TOrder save(TOrder po) {
    // 扣余额
    Long accountId = 1L;
    String result = accountFeignClient.decreaseMoney(po.getMoney(), accountId);
    log.Info("扣余额:{}, money:{}, accountId:{}",result,po.getMoney(),accountId);
    // 扣库存
    productFeginClient.decreaseNum(po.getNum(), po.getProductId);
    log.Info("扣库存:{}, num:{}, productId:{}",result, po.getNum(), po.getProductId());
    // 下单
    TOrder order = tOrder.save();
    log.Info("下单:success");
    return order;
}

TCC模式

      TCC 模式需要用户根据自己的业务场景实现try()、confirm()和cancel()这3个方法:事务发起方在一阶段执行try()方法,在二阶段提交执行confirm()方法,在二阶段回滚执行cancel()方法。

用户以 TCC 模式接入 Seata 框架,最重要的是考虑如何将自己的业务模型拆成两阶段来实现。

      TCC 模式与 AT 模式的最主要区别如下:

  • 在使用上,TCC 模式依赖用户自行实现的3个方法,成本较大;AT 模式依赖全局事务注解和代理数据源,代码基本不需要改动,对业务无侵入,接入成本极低;
  • TCC 模式的作用范围在应用层,本质上是实现针对某种业务逻辑的正向和反向方法;AT 模式的作用范围在底层数据源,通过保存操作行记录的前、后镜像和生成反向 SQL 语句进行补偿操作,对上层应用透明;
  • TCC 模式事务并发控制由业务自行加锁,AT 模式由 Seata 框架自行加锁。

      以扣款为例说明 TCC 模式。在接入 TCC 模式之前,只需要一条更新账户余额的 SQL 语句就能完成;但是接入 TCC 模式之后,用户则需要考虑将原来一步就能完成的扣款操作拆成两阶段,实现3个方法,并且保证如果一阶段 try() 方法成功则二阶段 confirm() 方法也一定能成功。如下图所示:
请输入图片描述

  • try() 方法在一阶段执行,需要做资源的检查和预留。比如检查账户余额是否充足、预留转账资金(冻结转账金额)。比如此处在执行 try() 方法后,账户A的余额虽然还是100元,但是其中有30元已经被冻结了,不能被其他事务使用。
  • 二阶段 confirm() 方法执行真正的扣款操作。confirm() 方法会使用 try() 方法冻结的金额执行扣款。在 confirm() 方法执行后,账户A在一阶段中冻结的30元已经被扣除,账户A的余额变为70元。
  • 如果二阶段回滚,则需要执行 cancel() 方法释放一阶段 try() 方法冻结的30元,使得账户A的余额回到初始状态(100元)。

Saga模式

      Saga 模式是一种补偿协议。在 Saga 模式中,在分布式事务内有多个参与者,每个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向和逆向回滚操作。
      如下图所示,T1~T3 都是正向的业务流程,都对应着一个冲正逆向操作 C1~C3。
请输入图片描述

      在分布式事务执行过程中,会依次执行各参与者的正向操作:

  • 如果所有正向操作均执行成功,则分布式事务提交;
  • 如果任何一个正向操作执行失败,则分布式事务会退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。

      Saga 模式的优势:

  • 在一阶段提交本地数据库事务,无锁,高性能
  • 参与者可以采用事件驱动异步执行,高吞吐
  • 补偿服务即正向服务的"反向"操作,易于理解,易于实现

      Saga 模式也存在很明显的缺点:在一阶段已经提交了本地数据库事务,且没有进行"预留"动作,所以不能保证隔离性,不容易进行并发控制。与 AT 模式和 TCC 模式相比,Saga 模式的适用场景有限。

XA模式

      在 XA 模式中,需要在 Seata 定义的分布式事务范围内,利用事务资源实现对 XA 协议的支持,以 XA 协议的机制来管理分支事务。

本质上,Seata 的 AT、TCC、Saga模式都是补偿型的。事务处理机制构建在框架或应用中。事务资源本身对分布式事务是无感知的。而在 XA 模式下,事务资源对分布式事务是可感知的。

Last modification:December 5th, 2021 at 07:13 pm
如果觉得我的文章对你有用,请随意赞赏