SpringCloud整合seata

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

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 Transaction

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>

 

 

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值