还不会分布式事务,seata xa模式入门实战送上


前言

目前微服务的火热程度不用多说,简历上不写个熟悉Spring Cloud的框架感觉都没有竞争力。但是玩了这么久的微服务,其中关键的分布式事务问题,你真的掌握了吗?

今天带大家使用seata xa模式轻松解决分布式事务问题。


一、什么是seata?

Seata 是阿里打造的一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

二、seata原理说明

1、角色说明

Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。

  • TC (Transaction Coordinator) - 事务协调者
    维护全局和分支事务的状态,驱动全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器
    定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器
    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
    在这里插入图片描述

2、什么是 Seata 的事务模式?

Seata 定义了全局事务的框架。

全局事务 定义为若干 分支事务 的整体协调:
1、TM 向 TC 请求发起(Begin)、提交(Commit)、回滚(Rollback)全局事务。
2、TM 把代表全局事务的 XID 绑定到分支事务上。
3、RM 向 TC 注册,把分支事务关联到 XID 代表的全局事务中。
4、RM 把分支事务的执行结果上报给 TC。(可选)
5、TC 发送分支提交(Branch Commit)或分支回滚(Branch Rollback)命令给 RM。

Seata 的 全局事务 处理过程,分为两个阶段:
1、执行阶段 :执行 分支事务,并 保证 执行结果满足是 可回滚的(Rollbackable) 和 持久化的(Durable)。
2、完成阶段: 根据 执行阶段 结果形成的决议,应用通过 TM 发出的全局提交或回滚的请求给 TC,TC 命令 RM 驱动 分支事务 进行 Commit 或 Rollback。

Seata 的所谓 事务模式 是指:运行在 Seata 全局事务框架下的 分支事务 的行为模式。准确地讲,应该叫作 分支事务模式。
不同的 事务模式 区别在于 分支事务 使用不同的方式达到全局事务两个阶段的目标。即,回答以下两个问题:
1、执行阶段 :如何执行并 保证 执行结果满足是 可回滚的(Rollbackable) 和 持久化的(Durable)。
2、完成阶段: 收到 TC 的命令后,如何做到分支的提交或回滚?

以我们 Seata 的 AT 模式和 TCC 模式为例来理解:
AT 模式:

  • 执行阶段:
    可回滚:根据 SQL 解析结果,记录回滚日志
    持久化:回滚日志和业务 SQL 在同一个本地事务中提交到数据库

  • 完成阶段:
    分支提交:异步删除回滚日志记录
    分支回滚:依据回滚日志进行反向补偿更新

TCC 模式:

  • 执行阶段

调用业务定义的 Try 方法(完全由业务层面保证 可回滚 和 持久化)

  • 完成阶段:
    分支提交:调用各事务分支定义的 Confirm 方法
    分支回滚:调用各事务分支定义的 Cancel 方法

三、SEATA 的分布式案例

1、业务逻辑说明

用户购买商品的业务逻辑。整个业务逻辑由4个微服务提供支持:
交易服务(Business):购买商品,发起交易,开启全局事务,作为TM
仓储服务(Storage):对给定的商品扣除仓储数量。作为RM
订单服务(Order):根据采购需求创建订单。作为RM
帐户服务(Account):从用户帐户中扣除余额。作为RM
seate server作为TC事务协调者,维护全局和分支事务的状态

2、架构图

在这里插入图片描述

3、SEATA 的分布式交易解决方案

在这里插入图片描述
具体的执行流程如下:
1、交易服务接收到购买请求,作为TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID。
2、交易服务向库存服务(Storage)和订单服务(Order)发起RPC请求。(XID在微服务调用链路的上下文中传播)
3、库存服务(Storage)和订单服务(Order)向TC注册分支事务,并执行扣减库存,生产订单的业务逻辑,并将其纳入XID对应的全局事务的管辖。
4、订单服务(Order)向账户服务(Account)发起请求扣减账户余额,账户服务(Account)向TC注册分支事务,执行扣减账户余额操作。
5、账户服务(Account),订单服务(Order),库存服务(Storage)分支事务执行完毕。
6、TM向TC发起针对XID的全局提交或回滚决议。
7、TC调度XID下管辖的全部分支事务完成提交或回滚请求。

四、Seata XA模式说明

Seata 1.2.0 版本重磅发布新的事务模式:XA 模式,实现对 XA 协议的支持。

1、什么是 XA?

XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准。

XA 规范 描述了全局的事务管理器与局部的资源管理器之间的接口。XA规范 的目的是允许的多个资源(如数据库,应用服务器,消息队列等)在同一事务中访问,这样可以使 ACID 属性跨越应用程序而保持有效。

XA 规范 使用两阶段提交(2PC,Two-Phase Commit)来保证所有资源同时提交或回滚任何特定的事务。

XA 规范 在上世纪 90 年代初就被提出。目前,几乎所有主流的数据库都对 XA 规范 提供了支持。

2、什么是 Seata 的 XA 模式?

XA 模式:
在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。

执行阶段:
可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)

完成阶段:
分支提交:执行 XA 分支的 commit
分支回滚:执行 XA 分支的 rollback

3、为什么支持 XA ?

为什么要在 Seata 中增加 XA 模式呢?支持 XA 的意义在哪里呢?
1、补偿型事务模式的问题
本质上,Seata 已经支持的 3 大事务模式:AT、TCC、Saga 都是 补偿型 的。
补偿型 事务处理机制构建在 事务资源 之上(要么在中间件层面,要么在应用层面),事务资源 本身对分布式事务是无感知的。

事务资源 对分布式事务的无感知存在一个根本性的问题:无法做到真正的 全局一致性 。

比如,一条库存记录,处在 补偿型 事务处理过程中,由 100 扣减为 50。此时,仓库管理员连接数据库,查询统计库存,就看到当前的 50。之后,事务因为异外回滚,库存会被补偿回滚为 100。显然,仓库管理员查询统计到的 50 就是 脏 数据。

可以看到,补偿型 分布式事务机制因为不要求 事务资源 本身(如数据库)的机制参与,所以无法保证从事务框架之外的全局视角的数据一致性。

2、XA 的价值
与 补偿型 不同,XA 协议 要求 事务资源 本身提供对规范和协议的支持。

因为 事务资源 感知并参与分布式事务处理过程,所以 事务资源(如数据库)可以保障从任意视角对数据的访问有效隔离,满足全局数据一致性。

比如,上一节提到的库存更新场景,XA 事务处理过程中,中间态数据库存 50 由数据库本身保证,是不会仓库管理员的查询统计 看 到的。(当然隔离级别需要 读已提交 以上)

除了 全局一致性 这个根本性的价值外,支持 XA 还有如下几个方面的好处:
1、业务无侵入:和 AT 一样,XA 模式将是业务无侵入的,不给应用设计和开发带来额外负担。
2、数据库的支持广泛:XA 协议被主流关系型数据库广泛支持,不需要额外的适配即可使用。
3、多语言支持容易:因为不涉及 SQL 解析,XA 模式对 Seata 的 RM 的要求比较少,为不同语言开发 SDK 较之 AT 模式将更 薄,更容易。
4、传统基于 XA 应用的迁移:传统的,基于 XA 协议的应用,迁移到 Seata 平台,使用 XA 模式将更平滑。

4、XA 模式的前提

  1. 支持XA 事务的数据库。
  2. Java 应用,通过 JDBC 访问数据库。

5、XA 整体机制

在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。
在这里插入图片描述
执行阶段:
可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)

完成阶段:
分支提交:执行 XA 分支的 commit
分支回滚:执行 XA 分支的 rollback

6、XA 工作机制

1. 整体运行机制

XA 模式 运行在 Seata 定义的事务框架内:
在这里插入图片描述
执行阶段(E xecute):
XA start/XA end/XA prepare + SQL + 注册分支

完成阶段(F inish):
XA commit/XA rollback

2. 数据源代理

XA 模式需要 XAConnection。

五、seata server安装

1、下载最新版本的 Seata Sever
这里我下载的是最新版seata-server-1.4.1

2、解压并启动 Seata server

unzip seata-server-1.4.1.zip

cd seate/bin

sh seata-server.sh -p 8091 -h 127.0.0.1 -m file

配置暂时不做任何修改。默认会采用file存储模式。

六、项目实战

可以参考 Seata 官网的样例:seata-xa
不知道大家下载后能否运行,反正我是折腾半天,还是启动失败。最后参考着自己对项目进行重建。

1、执行sql/all_in_one.sql,建立相关业务表
sql存放的地址:all_in_one.sql
在这里插入图片描述

2、构建工程seata-xa
在这里插入图片描述
3、maven依赖
需要注意一下问题:
3.1 Spring boot和Spring Cloud的版本对应关系
在这里插入图片描述
这里我采用的是Spring Boot 2.2.6.RELEASE,Spring Cloud采用的Hoxton.SR10
在这里插入图片描述
3.2 没有采用官网demo中的spring-cloud-alibaba-seata,而是seata-spring-boot-starter 1.4.1
经尝试采用spring-cloud-alibaba-seata时,项目启动一直报错,暂时没有找到解决办法。
seata-spring-boot-starter的版本选用1.4.1,这样才支持DataSourceProxyXA。并且可以和seata-server-1.4.1版本对应上。
在这里插入图片描述

4、添加seate相关属性

seata.tx-service-group=my_test_tx_group
seata.data-source-proxy-mode=XA
seata.registry.type=file

属性说明:
seata.tx-service-group属性是配置seata事务服务的分组名称,需要和seate server的配置保持一直。默认值为my_test_tx_group。
seata.data-source-proxy-mode属性用来指定数据源的代理模式,支持AT和XA,如果选择AT模式的话,需要在数据源中创建undo_log事务回滚日志表。
seata.registry.type属性用来指定seata的注册中心的类型,目前支持file,nacos,eureka,redis,zk等多种模式,默认为file。

5、数据源的配置类都可以省略
seata-spring-boot-starter会自动根据配置seata.data-source-proxy-mode启用不同的数据源代理。
不需要在代码中进行控制。

@Bean("dataSource")
public DataSource dataSource(DruidDataSource druidDataSource) {
    // DataSourceProxy for AT mode
    // return new DataSourceProxy(druidDataSource);

    // DataSourceProxyXA for XA mode
    return new DataSourceProxyXA(druidDataSource);
}

6、在发起分布式事务请求的方法上添加@GlobalTransactional 注解,开启全局事务
需要使用一个 @GlobalTransactional 注解在业务方法上:

@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount) {
    ......
}

7、在发起分布式事务请求的方法上添加@GlobalTransactional 注解,开启全局事务
需要使用一个 @GlobalTransactional 注解在业务方法上:

@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount) {
    ......
}

8、分支事务上,添加@Transactional注解

@Transactional(rollbackFor = Exception.class)
public void reduce(String userId, int money) {
    String xid = RootContext.getXID();
    log.info("reduce account balance in transaction: " + xid);
    jdbcTemplate.update("update account_tbl set money = money - ? where user_id = ?", new Object[] {money, userId});
    int balance = jdbcTemplate.queryForObject("select money from account_tbl where user_id = ?", new Object[] {userId}, Integer.class);
    log.info("balance after transaction: " + balance);
    if (balance < 0) {
        throw new RuntimeException("Not Enough Money ...");
    }
}

9、启动四个项目
在这里插入图片描述
10、发起请求校验分布式事务
发起购买请求:http://127.0.0.1:8020/purchase

基于初始化数据,和默认的调用逻辑,purchase 将可以被成功调用 3 次。

每次账户余额扣减 3000,由最初的 10000 减少到 1000。

第 4 次调用,因为账户余额不足,purchase 调用将失败。相应的:库存、订单、账户都回滚。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

项目地址:seata-xa

总结

本文主要介绍了seata xa的工作原理和实战使用方法。
相比其他seata其他3中模式,xa模式最大的优点就是业务无侵入,满足全局数据一致性。但相应的,xa模式需要数据库支持XA协议,性能较差,对长事务支持较差。

在当前的技术发展阶段,不存一个分布式事务处理机制可以完美满足所有场景的需求。
一致性、可靠性、易用性、性能等诸多方面的系统设计约束,需要用不同的事务处理机制去满足。
Seata 项目最核心的价值在于:构建一个全面解决分布式事务问题的标准化平台。
XA 模式的加入,补齐了 Seata 在 全局一致性 场景下的缺口,形成 AT、TCC、Saga、XA 四大 事务模式 的版图,基本可以满足所有场景的分布式事务处理诉求。

我始终认为一个技术只有自己实际会用,功能跑起来的,才算是入门了,后续会出更多实战类的文章,欢迎关注评论交流。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斗者_2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值