【分布式事务】分布式事务Seata

客官°小女子只卖身不卖艺 2023-10-09 13:49 139阅读 0赞

文章目录

  • 前言
  • 什么是分布式事务?
    • (1)数据库分库分表就产生了分布式事务;
    • (2)项目拆分服务化也产生了分布式事务;
  • 一、What is seata?
    • (1)TC (Transaction Coordinator) - 事务协调者
    • (2)TM (Transaction Manager) - 事务管理器
    • (3)RM (Resource Manager) - 资源管理器
    • (4) 在Seata中,一个分布式事务的生命周期如下:
  • 二、Seata TC Server运行环境部署
    • (1)TC有三种存储模式
    • (2)安装步骤
  • 三、AT模式事务案例
    • (1)单体应用多数据源分布式事务
    • (2)微服务的分布式事务
    • (3)AT事务模式分布式事务工作机制
  • 三、TCC 模式事务案例
    • (1)单体应用多数据源分布式事务
    • (2)基于SpringBoot单体应用的TCC事务
    • (3)基于Spring Cloud Alibaba的TCC分布式事务

前言

想要学习Seata 前首先要对了解分布式事务有一定的了解。
其次了解seata的架构模型
然后了解AT 模式、TCC 模式、知道SAGA 模式、并知道高可用的搭建等。

什么是分布式事务?

事务是数据库的概念,数据库事务(ACID:原子性、一致性、隔离性和持久性);
分布式事务的产生,是由于数据库的拆分和分布式架构(微服务)带来的,在常规情况下,我们在一个进程中操作一个数据库,这属于本地事务,如果在一个进程中操作多个数据库,或者在多个进程中操作一个或多个数据库,就产生了分布式事务;

(1)数据库分库分表就产生了分布式事务;

在这里插入图片描述

(2)项目拆分服务化也产生了分布式事务;

在这里插入图片描述

一、What is seata?

Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务;
Seata为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案;
四种事务模式中,XA模式正在开发中…,其他事务模式已经实现;
目前使用的流行度情况是:AT > TCC > Saga;
我们可以参看seata各公司使用列表:
https://github.com/seata/seata/issues/1246 大部分公司都采用的AT事务模式;
Seata已经在国内很多团队开始落地,其中不乏有大公司;
Github:https://github.com/seata/seata
官网:http://seata.io/
本文章介绍的版本:1.3.0

在Seata的架构中,一共有三个角色
在这里插入图片描述

(1)TC (Transaction Coordinator) - 事务协调者

  • 维护全局和分支事务的状态,驱动全局事务提交或回滚;

(2)TM (Transaction Manager) - 事务管理器

  • 定义全局事务的范围:开始全局事务、提交或回滚全局事务;

(3)RM (Resource Manager) - 资源管理器

  • 管理分支事务处理的资源,与TC交互以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚;

其中TC为单独部署的Server服务端,TM和RM为嵌入到应用中的Client客户端;

(4) 在Seata中,一个分布式事务的生命周期如下:

在这里插入图片描述

  • TM请求TC开启一个全局事务,TC会生成一个XID作为该全局事务的编号,XID会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起
  • RM请求TC将本地事务注册为全局事务的分支事务,通过全局事务的XID进行关联;
  • TM请求TC告诉XID对应的全局事务是进行提交还是回滚;
  • TC驱动RM将XID对应的自己的本地事务进行提交还是回滚;

二、Seata TC Server运行环境部署

(1)TC有三种存储模式

我们先部署单机环境的 Seata TC Server,用于学习或测试,在生产环境中要部署集群环境;
因为TC需要进行全局事务和分支事务的记录,所以需要对应的存储,目前,TC有三种存储模式( store.mode ):

  • file模式:适合单机模式,全局事务会话信息在内存中读写,并持久化本地文件 root.data,性能较高;
  • db模式:适合集群模式,全局事务会话信息通过 db 共享,相对性能差点;
  • redis模式:解决db存储的性能问题;
    我们先采用file模式,最终我们部署单机TC Server如下图所示:
    在这里插入图片描述

(2)安装步骤

  • 下载Seata:http://seata.io/zh-cn/blog/download.html
  • 下载好后 上传到自己的云服务器上解压:tar -zxvf seata-server-1.3.0.tar.gz
  • 解压后切换 cd seata
    在这里插入图片描述
  • 默认seata-server.sh脚本设置的jvm内存参数2G,我们再做实验,可以改小一点;
    在这里插入图片描述
  • 在bin目录下启动:./seata-server.sh
    默认配置下,Seata TC Server 启动在 8091 端口;
    因为我们没有修改任何配置文件,默认情况seata使用的是file模式进行数据持久化,所以可以看到用于持久化的本地文件 root.data;

    代码如下(示例):

三、AT模式事务案例

(1)单体应用多数据源分布式事务

在这里插入图片描述

在Spring Boot单体项目中,如果使用了多数据源,就需要考虑多个数据源的数据一致性,即产生了分布式事务的问题,我们采用Seata的AT事务模式来解决该分布式事务问题;
以电商购物下单为例:
在这里插入图片描述
1、准备数据库表和数据;
其中每个库中的undo_log表,是 Seata AT模式必须创建的表,主要用于分支事务的回滚;
2、开发一个SpringBoot单体应用;
在这里插入图片描述

(2)微服务的分布式事务

在这里插入图片描述

(3)AT事务模式分布式事务工作机制

  • 前提
    基于支持本地 ACID 事务的关系型数据库;(mysql、oracle)
    Java 应用,通过JDBC访问数据库;
  • 整体机制
    就是两阶段提交协议的演变:
    • 一阶段:
      “业务数据“和“回滚日志记录“在同一个本地事务中提交,释放本地锁和连接资源;
    • 二阶段:
      如果没有异常异步化提交,非常快速地完成;
      如果有异常回滚通过一阶段的回滚日志进行反向补偿;
  • 具体举例说明整个AT分支的工作过程:

(1)创建如下数据库表

  1. 业务表:product
  2. Field Type Key
  3. id bigint(20) PRI
  4. name varchar(100)
  5. since varchar(100)

-AT分支事务的业务逻辑:

  1. update product set name = 'GTS' where name = 'TXC';
    • 一阶段过程:

    updat
    1、解析SQL,得到SQL的类型(UPDATE),表(product),条件(where name = ‘TXC’)等相关的信息;
    2、查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据;

    1. select id, name, since from product where name = 'TXC';
    2. 得到前镜像:
    3. id name since
    4. 1 TXC 2014

    3、执行业务 SQL:更新这条记录的 name 为 ‘GTS’;
    4、查询后镜像:根据前镜像的结果,通过 主键 定位数据;
    select id, name, since from product where id = 1;
    得到后镜像:

    1. id name since
    2. 1 GTS 2014

    5、插入回滚日志:把前后镜像数据以及业务SQL相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中;
    6、分支事务提交前,向TC注册分支,申请product表中,主键值等于1的记录的全局锁(在当前的同一个全局事务id范围内是可以申请到全局锁的,不同的全局事务id才会排斥);
    7、本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交;
    8、将本地事务提交的结果上报给TC;

    • 二阶段-回滚:

    1、收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作;
    2、通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录;
    3、数据校验:拿 UNDO LOG 中的后镜像与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改,这种情况,需要人工来处理;
    4、根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
    update product set name = ‘TXC’ where id = 1;
    5、提交本地事务,并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC;

    • 二阶段-提交:
  • 1、收到TC的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给TC;
  • 2、异步任务阶段的分支提交请求将异步和批量地删除相应UNDO LOG记录;
  • 回滚日志表:

    Field Type
    branch_id bigint PK
    xid varchar(100)
    context varchar(128)
    rollback_info longblob
    log_status tinyint
    log_created datetime
    log_modified datetime

  • SQL建表语句:

    CREATE TABLE undo_log (
    id bigint NOT NULL AUTO_INCREMENT,
    branch_id bigint NOT NULL,
    xid varchar(100) NOT NULL,
    context varchar(128) NOT NULL,
    rollback_info longblob NOT NULL,
    log_status int NOT NULL,
    log_created datetime NOT NULL,
    log_modified datetime NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY ux_undo_log (xid,branch_id)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

三、TCC 模式事务案例

(1)单体应用多数据源分布式事务

  • AT模式基本上能满足我们使用分布式事务大部分需求,但涉及非关系型数据库与中间件的操作、跨公司服务的调用、跨语言的应用调用就需要结合TCC模式;
  • 在这里插入图片描述
  • 一个分布式的全局事务,整体是两阶段提交(Try - [Comfirm/Cancel])的模型,在Seata中,AT模式与TCC模式事实上都是基于两阶段提交,它们的区别在于:

AT模式基于支持本地ACID事务的关系型数据库:

    • 1、一阶段prepare行为:在本地事务中,一并提交“业务数据更新“和”相应回滚日志记录”;
    • 2、二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志;
    • 3、二阶段 rollback 行为:通过回滚日志,自动生成补偿操作,完成数据回滚;

而TCC 模式,需要我们人为编写代码实现提交和回滚:

    • 1、一阶段 prepare 行为:调用自定义的 prepare 逻辑;(真正要做的事情,比如插入订单,更新库存,更新余额)
    • 2、二阶段 commit 行为:调用自定义的 commit 逻辑;(自己写代码实现)
    • 3、二阶段 rollback 行为:调用自定义的 rollback 逻辑;(自己写代码实现)
      所以TCC模式,就是把自定义的分支事务的提交和回滚并纳入到全局事务管理中;
      通俗来说,Seata的TCC模式就是手工版本的AT模式,它允许你自定义两阶段的处理逻辑而不需要依赖AT模式的undo_log回滚表;

(2)基于SpringBoot单体应用的TCC事务

在这里插入图片描述

  1. /**
  2. * 下订单时扣除越的方法
  3. */
  4. @LocalTCC
  5. public interface AccountService {
  6. /**
  7. * 扣除余额
  8. * 定义两阶段提交
  9. * name = reduceStock为一阶段try方法
  10. * commitMethod = commitTcc 为二阶段确认方法
  11. * rollbackMethod = cancel 为二阶段取消方法
  12. * BusinessActionContextParameter注解 可传递参数到二阶段方法
  13. *
  14. * @param userId 用户ID
  15. * @param money 扣减金额
  16. * @throws Exception 失败时抛出异常
  17. */
  18. @TwoPhaseBusinessAction(name = "reduceBalance", commitMethod = "commitTcc", rollbackMethod = "cancelTcc")
  19. void reduceBalance(@BusinessActionContextParameter(paramName = "userId") Integer userId,
  20. @BusinessActionContextParameter(paramName = "money") BigDecimal money);
  21. /**
  22. * 确认方法、可以另命名,但要保证与commitMethod一致
  23. * context可以传递try方法的参数
  24. *
  25. * @param context 上下文
  26. * @return boolean
  27. */
  28. boolean commitTcc(BusinessActionContext context);
  29. /**
  30. * 二阶段取消方法
  31. *
  32. * @param context 上下文
  33. * @return boolean
  34. */
  35. boolean cancelTcc(BusinessActionContext context);
  36. }
  • @LocalTCC 注解标识此TCC为本地模式,即该事务是本地调用,非RPC调用,@LocalTCC一定需要注解在接口上,此接口可以是寻常的业务接口,只要实现了TCC的两阶段提交对应方法即可;
  • @TwoPhaseBusinessAction,该注解标识为TCC模式,注解try方法,其中name为当前tcc方法的bean名称,写方法名便可(全局唯一),commitMethod指提交方法,rollbackMethod指事务回滚方法,指定好三个方法之后,Seata会根据事务的成功或失败,通过动态代理去帮我们自动调用提交或者回滚;
  • @BusinessActionContextParameter注解可以将参数传递到二阶段(commitMethod/rollbackMethod)的方法;
  • BusinessActionContext是指TCC事务上下文,携带了业务方法的参数;

(3)基于Spring Cloud Alibaba的TCC分布式事务

在这里插入图片描述
具体代码实现和springboot单体应用的代码实现几乎没有区别,具体参考Git上提交的代码;

发表评论

表情:
评论列表 (有 0 条评论,139人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Seata--分布式事务

    1、Seata 分布式事务基础 1.1事务 事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操作都成功,要么所有的操作都被撤销。简