Seata四种事务模式AT、TCC、SAGA 、 XA详解

文章目录

  • 一、 @GlobalTransactional
  • 一、AT模式
    • 1、原理
    • 2 、优缺点
    • 3、实现
  • 二、TCC模式
    • 1、原理
    • 2 、优缺点
    • 3、实现
  • 三、SAGA模式
    • 1 、原理
    • 2 、优缺点
    • 3 、实现
  • 四、XA模式
    • 1 、原理
    • 2 、优缺点
    • 3、 实现
  • 五、 四种模式对比

我们知道Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA四种事务模式,为用户打造一站式的分布式解决方案,包括事务管理、本地事务协调、分布式事务日志和分布式锁等组件。

之前我们学习了Seata的简介、Seata客户端和服务端的搭建集成、本篇文章我们了解一下Seata是如何通过四种事务模式解决分布式事务问题的。

一、 @GlobalTransactional

Spring本地事务使用:@Transactional
Seata全局事务使用:@GlobalTransactional

继续以我们之前搭建的用户购买商品微服务系统【微服务整合Seata1.5.2+Nacos2.2.1+SpringBoot】为例:
仓储服务(Stock):对给定的商品扣除仓储数量。
订单服务(Order):根据采购需求创建订单。
账户服务(Account):从用户账户中扣除余额。

创建订单->调用库存服务扣减库存->调用账户服务扣减账户余额->修改订单状态
简单说:下订单->扣库存->减余额->改状态

假设第3步扣减账户超时,在seata-account-service项目中模拟一个异常。不加 @GlobalTransactional 事务控制出现超时会数据异常,当库存和账户金额扣减后,订单状态并没有设置为已经完成,没有从零改为 1。而且由于 feign 的重试机制,账户余额还有可能被多次扣减。

Seata四种事务模式AT、TCC、SAGA 、 XA详解_第1张图片
接下来加上加 @GlobalTransactional,注意每个应用都使用Seata对数据源进行代理,再次请求,发现全局事务回滚成功。

/**
 * 使用Seata对数据源进行代理
 */
@Configuration

public class DataSourceProxyConfig {
        @Value("${mybatis-plus.mapper-locations}")
        private String mapperLocations;

        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource druidDataSource(){
            return new DruidDataSource();
        }

        @Bean
        public DataSourceProxy dataSourceProxy(DataSource dataSource) {
            return new DataSourceProxy(dataSource);
        }

        @Bean
        public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dataSourceProxy);
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources(mapperLocations));
            sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
            return sqlSessionFactoryBean.getObject();
        }
}

Seata四种事务模式AT、TCC、SAGA 、 XA详解_第2张图片

如果未成功,先检查异常是否被catch或者有无熔断降级。

一、AT模式

1、原理

AT模式前提:
基于支持本地 ACID 事务的关系型数据库。
Java 应用,通过 JDBC 访问数据库。

两阶段提交协议的演变
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。

AT模式是一种分布式事务处理模式,它通过在每个参与者的本地事务中实现事务的原子性和隔离性,来保证分布式事务的一致性。AT模式避免了全局锁和阻塞的问题,从而提高了系统的并发性能。在AT模式中,参与者的本地事务执行成功后即可提交,而不需要等待其他参与者的状态。

AT模式的原理如下
事务的发起者开始一个全局事务,并在本地事务管理器中开始一个本地事务。
事务的发起者调用其他参与者的服务,将全局事务ID传递给它们。
参与者接收到全局事务ID后,在本地事务管理器中开始一个本地事务,并执行操作。
当参与者的本地事务执行成功时,将操作结果记录在本地日志中。
事务的发起者完成所有参与者的服务调用后,调用各个参与者的提交接口。
参与者检查本地事务的日志记录,如果操作都成功,则提交本地事务;否则,回滚本地事务。

seata的AT模式:Seata的AT模式是在AT模式基础上进行了扩展和优化的实现。Seata引入了Seata Server和Seata Client的概念,通过Seata Server作为事务协调器,集中管理分布式事务的控制逻辑。Seata的AT模式还提供了更多的功能和工具,如分布式事务日志和分布式锁,以增强分布式事务的可靠性和性能。

2 、优缺点

优点

  • 较高的性能:AT模式在每个参与者的本地事务中执行操作,避免了全局锁和阻塞的问题,提高了系统的并发性能。
  • 简化的实现:相对于XA模式,AT模式的实现相对简单,不需要涉及全局事务协调器,减少了开发和维护的复杂性。
  • 本地事务的独立性:每个参与者在本地事务管理器中管理自己的事务,可以独立控制和优化本地事务的执行。

缺点

  • 弱一致性:AT模式对一致性的要求相对较低,可能会出现数据不一致的情况。在某些场景下,可能需要更高的一致性保证,需要考虑其他分布式事务处理模式。
  • 隔离级别限制:由于AT模式依赖于本地事务的隔离性,参与者的隔离级别受限于本地事务管理器支持的隔离级别,可能无法满足某些特定的隔离需求。
  • 容错性和恢复性:AT模式在发生故障或错误时,需要考虑如何处理事务的回滚和恢复,以确保数据的一致性和可靠性。

3、实现

添加配置seata:data-source-proxy-mode: AT
在需要分布式事务的业务代码上添加注解@GlobalTransactional
重启测试

二、TCC模式

1、原理

TCC模式是一种分布式事务处理模式,用于解决分布式环境下的一致性问题。它通过将事务分解为三个阶段(Try、Confirm、Cancel)来实现事务的可靠性和一致性。使得每个参与者可以控制自己的操作和资源,从而实现了分布式事务的可靠性和一致性。它要求参与者实现相应的接口和逻辑,确保Try和Cancel操作是幂等的,以处理重试和故障恢复情况。

AT 模式与TCC 模式
AT 模式(参考链接 TBD)基于 支持本地 ACID 事务 的 关系型数据库:
一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:
一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
二阶段 commit 行为:调用 自定义 的 commit 逻辑。
二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

TCC模式的工作原理如下

Try阶段(尝试阶段):在这个阶段,参与者(服务)尝试预留或锁定资源,并执行必要的前置检查。如果所有参与者的Try操作都成功,表示资源可用,并进入下一阶段。如果有任何一个参与者的Try操作失败,表示资源不可用或发生冲突,事务将中止。

Confirm阶段(确认阶段):在这个阶段,参与者进行最终的确认操作,将资源真正提交或应用到系统中。如果所有参与者的Confirm操作都成功,事务完成,提交操作得到确认。如果有任何一个参与者的Confirm操作失败,事务将进入Cancel阶段。

Cancel阶段(取消阶段):在这个阶段,参与者进行回滚或取消操作,将之前尝试预留或锁定的资源恢复到原始状态。如果所有参与者的Cancel操作都成功,事务被取消,资源释放。如果有任何一个参与者的Cancel操作失败,可能需要进行补偿或人工介入来恢复系统一致性。

seata的TCC模式:Seata的TCC模式是在TCC模式基础上进行了扩展和优化的实现。Seata引入了Seata Server作为事务协调器,集中管理分布式事务的控制逻辑。Seata的TCC模式还提供了分布式事务日志和分布式锁等功能,以增强事务的可靠性和性能。Seata的TCC模式可以更方便地集成到应用中,并提供了更好的事务管理和监控能力。

2 、优缺点

优点

  • 一阶段完成直接提交事务,释放数据库资源,性能好;
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强;
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库;

缺点

  • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
  • 软状态,事务是最终一致;
  • 需要考虑Confirm和Cancel的失败情况,做好幂等处理;

3、实现

以账户转账为例:

定义参与者接口:

public interface AccountService {
boolean tryTransfer(String fromAccount, String toAccount, double amount);
boolean confirmTransfer(String fromAccount, String toAccount, double amount);
boolean cancelTransfer(String fromAccount, String toAccount, double amount);
}

实现参与者逻辑:

public class AccountServiceImpl implements AccountService {
@Override
public boolean tryTransfer(String fromAccount, String toAccount, double amount) {
// 执行转账操作,预留转出账户金额,检查账户余额等
// 如果成功,返回 true;如果失败,返回 false
}
@Override
public boolean confirmTransfer(String fromAccount, String toAccount, double amount) {
// 确认转账操作,将预留金额转出
// 如果成功,返回 true;如果失败,返回 false
}
@Override
public boolean cancelTransfer(String fromAccount, String toAccount, double amount) {
// 取消转账操作,将预留金额回滚到账户
// 如果成功,返回 true;如果失败,返回 false
}
}

客户端调用:

// 获取Seata全局事务ID
String xid = RootContext.getXID();
// 开启全局事务
TransactionContext context = new TransactionContext();
context.setXid(xid);
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
try {
// 调用参与者的tryTransfer方法
boolean tryResult = accountService.tryTransfer(fromAccount, toAccount, amount);
if (tryResult) {
// 提交全局事务
tx.commit();
} else {
// 回滚全局事务
tx.rollback();
}
} catch (Exception e) {
// 异常时回滚全局事务tx.rollback();
}

三、SAGA模式

1 、原理

Saga模式是一种用于处理分布式事务的模式,它通过将长时间的、复杂的事务分解为多个小的、可逆的事务片段,以实现事务的一致性和可靠性。

在Saga模式中,每个事务片段称为一个补偿操作。每个补偿操作都与一个正向操作相对应,正向操作是事务的一部分,而补偿操作是用于撤销或修复正向操作的。Saga模式通过按照事务执行的顺序,依次执行正向操作和补偿操作,来确保事务在发生失败或异常时能够进行回滚或恢复。

Saga模式的执行过程如下

执行正向操作:按照事务的逻辑顺序,依次执行正向操作。每个正向操作都会记录事务的执行状态。
如果所有的正向操作都成功执行,则事务提交完成。
如果某个正向操作失败,将会触发相应的补偿操作。补偿操作会撤销或修复正向操作的影响。
执行补偿操作:按照逆序依次执行已经触发的补偿操作。补偿操作应该具备幂等性,以便可以多次执行而不会造成副作用。
如果所有的补偿操作都成功执行,则事务回滚完成。
如果补偿操作也失败,需要人工介入或其他手段来解决事务的一致性问题。

Seata的Saga模式
  Seata的Saga模式通过Seata框架来管理和协调分布式事务,提供了对事务的编排和状态管理的支持。它与Seata的其他特性(如AT模式、TCC模式)结合在一起,构成了Seata全面的分布式事务解决方案。

Seata的Saga模式相对于传统的Saga模式,具有以下特点

  • 集成性:Seata的Saga模式与Seata框架紧密集成,可以与Seata的其他特性一起使用,如分布式事务日志和分布式锁等。
  • 强一致性:Seata的Saga模式提供了强一致性的事务支持,确保事务的执行顺序和一致性。
  • 可靠性:Seata的Saga模式在补偿操作的执行过程中,支持重试和恢复机制,提高了事务的可靠性和恢复能力。

适用场景

业务流程长、业务流程多

参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

2 、优缺点

优点

  • 一阶段提交本地事务,无锁,高性能
  • 事件驱动架构,参与者可异步执行,高吞吐
  • 补偿服务易于实现,不用编写TCC中的三个阶段,实现简单

缺点

  • 没有锁,不保证隔离性,会有脏写;
  • 软状态持续时间不确定,时效性差;

3 、实现

使用Seata的Saga模式,需要进行以下步骤:

定义参与者接口:

public interface OrderService {
boolean createOrder(String orderId, String userId, String productId, int quantity);
boolean cancelOrder(String orderId);
}
public interface ProductService {
boolean reduceStock(String productId, int quantity);
boolean revertStock(String productId, int quantity);
}

实现参与者逻辑:

public class OrderServiceImpl implements OrderService {
@Override
public boolean createOrder(String orderId, String userId, String productId, int quantity) {
// 执行订单创建逻辑,如创建订单记录、扣减用户余额等
// 如果成功,返回 true;如果失败,返回 false
}
@Override
public boolean cancelOrder(String orderId) {
// 执行订单取消逻辑,如回滚订单记录、恢复用户余额等
// 如果成功,返回 true;如果失败,返回 false
}
}
public class ProductServiceImpl implements ProductService {
@Override
public boolean reduceStock(String productId, int quantity) {
// 执行减少库存逻辑,如更新产品库存、记录库存变更日志等
// 如果成功,返回 true;如果失败,返回 false
}
@Override
public boolean revertStock(String productId, int quantity) {
// 执行恢复库存逻辑,如恢复产品库存、删除库存变更日志等
// 如果成功,返回 true;如果失败,返回 false}
}

客户端调用:

// 获取Seata全局事务ID
String xid = RootContext.getXID();
// 开启全局事务
TransactionContext context = new TransactionContext();
context.setXid(xid);
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
try {
// 调用参与者的方法
boolean createOrderResult = orderService.createOrder(orderId, userId, productId, quantity);boolean reduceStockResult = productService.reduceStock(productId, quantity);
if (createOrderResult && reduceStockResult) {
// 提交全局事务tx.commit();
} else {
// 回滚全局事务
tx.rollback();
}
} catch (Exception e) {// 异常时回滚全局事务tx.rollback();
}

四、XA模式

1 、原理

XA模式是一种分布式事务处理的协议,它使用两阶段提交(2PC)来保证事务的一致性和可靠性。

准备阶段:事务协调器向参与者发送准备请求,要求它们准备执行事务操作,并将结果记录在事务日志中。
提交阶段:如果所有参与者都准备就绪,事务协调器发送提交请求给参与者,要求它们执行事务的提交操作。
中断阶段:如果任何一个参与者未能准备就绪或发生错误,事务协调器发送中断请求给参与者,要求它们执行事务的中断操作。

通过两阶段提交,XA模式确保所有参与者要么一起提交事务,要么一起中断事务,从而保证事务的一致性。然而,XA模式也存在一些问题,如阻塞和单点故障的风险,因此在某些情况下可能需要考虑其他分布式事务解决方案。

2 、优缺点

优点

  • 一致性:XA模式通过两阶段提交协议,确保所有参与者要么一起提交事务,要么一起中断事务,从而保证事务的一致性。
  • 可靠性:XA模式提供了强一致性和可靠性的保证,在分布式环境下可以确保事务的正确执行。
  • 标准化:XA模式是一种标准的分布式事务处理协议,被广泛支持和应用于各种数据库和资源管理器中。

缺点

  • 性能开销:在XA模式中,需要进行多次网络通信和协调操作,这会引入额外的性能开销,并且可能会导致事务处理的延迟增加。
  • 阻塞风险:在准备阶段和提交阶段,所有的参与者都需要等待事务协调器的指令,这可能导致一些参与者在等待期间被阻塞,影响系统的吞吐量和并发性能。
  • 单点故障:在XA模式中,事务协调器起着关键的角色,如果事务协调器出现故障,整个分布式事务系统可能无法正常运行。

3、 实现

添加配置seata:data-source-proxy-mode: XA
在需要分布式事务的业务代码上添加注解@GlobalTransactional
从编程模型上,XA 模式与 AT 模式保持完全一致。只需要修改数据源代理,即可实现 XA 模式与 AT 模式之间的切换。
重启测试

五、 四种模式对比

XA AT TCC SAGA
一致性 强一致 弱一致 弱一致 最终一致
隔离性 完全隔离 基于全局锁隔离 基于资源预留隔离 无隔离
代码侵入 有,需要编写三个接口 有,需要编写状态机和补偿业务
性能 非常好 非常好
场景 对一致性、隔离性有高要求的业务 基于关系型数据库的大多数分布式务场景都可以 1.对性能要求较高的事务;
2.有非关系型数据库要参与的事务;
1.业务流程长、业务流程多;
2.参与者包含其它公司或遗留系统服务,无法提供TCC模式要求的三个接口

你可能感兴趣的:(spring,cloud,seata,分布式事务,java,微服务)