SpringCloud整合seata

  • Post author:
  • Post category:其他




常见的分布式事务解决方案:

1、seata阿里分布式事务框架

2、消息队列

3、saga

4、XA

他们都有一个共同点,都是”两阶段(2PC)”。两阶段是指完成整个分布式事务,划分成两个步骤完成,实际上这四种常见的分布式事务解决方案,分别对应着分布式事务的四种模式:AT、TCC、Saga、XA;四种分布式事务模式,都有各自的理论基础,分别在不同的时间被提出;每种模式都有他的适用场景,同样每个模式也都诞生有各自的代表产品,而这些代表产品,可能就是我们常见的(全局事务、基于可靠消息、最大努力通知、TCC)。

在看具体实现之前,先说下分布式事务的理论基础。



分布式事务理论基础

解决分布式事务,也有相应的规范和协议。分布式事务相关的协议有2PC、3PC。

由于三阶段提交协议3PC非常难实现,目前市面主流的分布式事务解决方案都是2PC协议。

有些文章分析2PC时,几乎都会用TCC两阶段的例子,第一阶段try,第二阶段完成confirm或cancel。其实2PC并不是专为实现TCC设计的,2PC具有普适性,目前绝大多数分布式事务解决方案都是以两阶段提交协议2PC为基础的。







两阶段提交协议









顾名思义,分为两个阶段:Prepare和Commit。








AT模式(Auto Tran






saction
















AT模式是一种




无侵入




的分布式事务解决方案。





阿里seata框架,实现了该模式。





在AT模式下,用户只需关注自己的业务sql,用户的业务sql作为一阶段,Seata框架会自动生成事务的二阶段提交和回滚操作。



AT模式如何做到对业务的无侵入:


一阶段:在一阶段,Seata会拦截业务sql,首先解析sql语义,找到业务sql要更新的业务数据,在业务数据被更新之前,将其保存成before image,然后执行业务sql更新业务数据,在业务数据更新之后,再将其保存成after image,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。


二阶段提交:二阶段如果是提交的话,因为业务sql在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁删除,完成数据清理即可。


二阶段回滚:二阶段如果是回滚的话,Seata就需要回滚一阶段已执行的业务sql,还原业务数据。回滚方式便是用before image 还原业务数据,但在还原前要首先校验脏写,对比数据库当前业务数据和after image,如果两份数据完全一致就说明没有脏写,可以还原业务数据。如果不一致,就说明有脏写,出现脏写就需要转人工处理。


AT模式的一阶段,二阶段提交和回滚都是由Seata框架自动生成,用户只需编写业务sql,便能轻松接入分布式事务,AT模式是一种对业务无任何侵入的分布式事务解决方案。




Seata





Seata是什么



Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)。




官网:



Seata




源码:



http://github.com/seata/seata



官方Demo:



GitHub – seata/seata-samples: seata-samples


Seata的三大角色


在Seata的架构中,一共有三大角色:


TC(Transaction Coordinator)- 事务协调者


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


TM(Transaction Manager)- 事务管理器


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


RM(Resource Manager)- 资源管理器


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


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


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


  1. TM请求TC开启一个全局事务。TC会生成一个XID作为该全局事务的编号。XID会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。

  2. RM请求TC将本地事务注册为全局事务的分支事务,通过全局事务的XID进行关联。

  3. TM请求TC告诉XID对应的全局事务是进行提交还是回滚。

  4. TC驱动RM们将XID对应的自己的本地事务进行提交还是回滚。







设计亮点









相比其他分布式事务框架,Seata架构的亮点主要有几个:




  1. 应用层基于sql解析实现了自动补偿,从而最大程度的降低业务侵入性。



  2. 将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚。



  3. 通过全局锁实现了写隔离和读隔离。







存在的问题






















性能损耗






一条update的sql,则需要全局事务xid获取(与TC通讯)、before image(解析sql,查询一次数据库)、after image(查询一次数据库)、insert undo log(写一次数据库)、before commit(与TC通讯,判断锁冲突),这些操作都需要运行一次远程通讯RPC,而且是同步的。另外undo log写入时blob字段的插入性能也是不高的。每条写sql都会增加这么多开销,粗略估计会增加5倍响应时间。







性价比










为了进行自动补偿,需要对所有交易生成前后镜像并持久化,可是在实际业务场景下,这个成功率是有多高,或者说分布式事务失败需要回滚的有多少比例?按照二八原则预估,为了20%的交易回滚,需要将80%的成功交易的响应时间增加5倍,这样的代价相比于让应用开发一个补偿交易是否是值得?







全局锁












Seata快速开始












Seata Server(TC)环境搭建








:












Server端存储模式(store.mode)支持三种








:








file:单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高(默认)



db:高可用模式,全局事务会话信息通过db共享,相应性能差些



redis:Seata-Server1.3及以上版本支持,性能较高。存在事务信息丢失风险,请提前配置适合当前场景的redis持久化配置



我们使用DB模式,是将数据存在数据库中。







db存储模式+Nacos高可用集群部署










步骤一:下载安装包




Tags · seata/seata · GitHub





步骤二:建表(仅db)





创建数据库seata-server



打开官网,找到资源目录









或者使用下面的文件:

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);



全局事务会话信息由3块内容构成,全局事务–>分支事务–>全局锁,对应表global_table、branch_table、lock_table。





步骤三:修改








conf中file.conf中的








store.mode








属性,








修改数据库连接








步骤

















:修改Server端配置注册中心








步骤五:








修改Server端配置中心





同样在registry.conf文件中修改注册中心为nacos





步骤

















:下载seata服务端源码




https://github.com/seata/seata/archive/refs/tags/v1.4.0.zip






步骤

















: 修改config.txt文件







发现默认的数据源时file






步骤


























配置事务分组






配置事务分组,要与客户端配置的事务分组一致。





对应的客户端配置


#事务分组配置

seata.tx-service-group=my_test_tx_group

#指定事务分组至集群映射关系(等号右侧的集群名需要与Seata-server注册到Nacos的cluster保持一致)

seata.service.vgroup-mapping.my_test_tx_group=default





步骤

















: 将config.txt文件中的配置导入到Nacos配置中心





打开




seata\seata-1.4.0\seata-1.4.0\script\config-center\nacos




文件夹



运行nacos-config.sh,前提1、先运行Nacos;2、装了Git






步骤十:启动SeataServer







启动Seata Server,双击seata-server.bat


















Seata Client








(项目代码)








环境搭建








  1. 启动seata server服务端,seata server使用nacos作为注册中心和配置中心(上一步已完成)



  2. 微服务整合seata



  • 添加pom依赖

<!–seata–>

<dependency>

<groupId>com.alibaba.cloud</groupId>

<artifactId>spring-cloud-starter-alibaba-seata</artifactId>

</dependency>



  1. 各微服务对应数据库中添加undo_log表



  2. 在配置文件修改事务分组



  3. 在application.yml文件中配置seata 的注册中心和配置中心

    spring:
    
      datasource:
    
        url: jdbc:mysql://localhost:3306/tw?characterEncoding=UTF-8&useSSL=false&useUnicode=true&serverTimezone=UTC
    
        username:username 
    
        password: password
    
        driver-class-name: com.mysql.jdbc.Driver
    
      profiles:
    
        # 当前环境,在真实项目中,一般分为多个环境,dev为开发环境
    
        active: dev
    
      application:
    
        name: 项目名
    
      cloud:
    
        alibaba:
    
          seata:
    
            #配置事务分组
    
            tx-service-group: my_test_tx_group
    
            #注册中心
    
            registry:
    
              #配置seata的注册中心为nacos,告诉seata client怎么去访问seata server
    
              type: nacos
    
              nacos:
    
                #seata server的注册地址
    
                server-addr: localhost:8848
    
                #seata server的服务名,默认:seata-server,若没有修改则可以不配置
    
                application: seata-server
    
                username: username
    
                password: password
    
                #seata server所在的组,默认:SEATA_GROUP,若没有修改则可以不配置
    
                group: SEATA_GROUP
    
            #配置中心
    
            config:
    
              #配置seata的配置中心为nacos
    
              type: nacos
    
              nacos:
    
                #seata server的注册地址
    
                server-addr: localhost:8848
    
                #seata server所在的组,默认:SEATA_GROUP,若没有修改则可以不配置
    
                group: SEATA_GROUP
    
                username: nacos
    
                password: nacos
    
        nacos:
    
          config:
    
            # 注册中心地址
    
            server-addr: localhost:8848
    
            # 配置文件后缀,即配置文件格式
    
            file-extension: yaml
    
            # 命名空间,在后续nacos配置中会出现该参数是如何获取的
    
            namespace: dcda1c6d-95b3-4581-96de-cc70583f228f  //nacos命名空间
    
          discovery:
    
            # 注册中心地址
    
            server-addr: localhost:8848
    
    
    
    #关闭驼峰
    
    mybatis-plus:
    
      configuration:
    
        map-underscore-to-camel-case: true
    
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
    
    
    #mybatis
    
    mybatis:
    
      type-aliases-package: com.tm.pojo #所有pojo类所在包的路径
    
      mapper-locations: classpath:mapper/*.xml #mapper映射文件
    
      configuration:
    
        map-underscore-to-camel-case: true #支持驼峰映射



  1. 在相应的服务




    中,要远程调用的方法上




    添加@GlobalTransactional注解



注:如果出现


就将所有配置文件中的127.0.0.1改为localhost即可,我改过,所以有问题,修改为localhost就好了



<dependency>





<groupId>com.alibaba.cloud</groupId>





<artifactId>spring-cloud-alibaba-dependencies</artifactId>





<version>2.2.5.RELEASE</version>





<type>pom</type>





<scope>import</scope>





</dependency>

子项目:




<dependency>





<groupId>




com.alibaba.cloud




</groupId>





<artifactId>




spring-cloud-starter-alibaba-seata




</artifactId>





</dependency>




版权声明:本文为weixin_70422105原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。