SpringCloudSpring Cloud Alibaba 之 Seata 分布式事务中间件(三十五)

Posted H__D

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloudSpring Cloud Alibaba 之 Seata 分布式事务中间件(三十五)相关的知识,希望对你有一定的参考价值。

什么是分布式事务问题?

单体应用

  单体应用中,一个业务操作需要调用三个模块完成,此时数据的一致性由本地事务来保证。

微服务应用

  随着业务需求的变化,单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。

小结

  在微服务架构中由于全局数据一致性没法保证产生的问题就是分布式事务问题。简单来说,一次业务操作需要操作多个数据源或需要进行远程调用,就会产生分布式事务问题。

Seata 是什么?

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

  官网:http://seata.io/

Seata 组成

Transaction ID(XID)

  全局唯一的事务id

三组件

  Transaction Coordinator(TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚

  Transaction Manager(TM):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议

  Resource Manager(RM):控制分支事务,负责分支注册、状态汇报,并接受事务协调的指令,驱动分支(本地)事务的提交和回滚

Seata 分布式事务处理过程

  过程图:

  

  说明:

  1、TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID;

  2、XID 在微服务调用链路的上下文中传播;

  3、RM 向 TC 注册分支事务,将其纳入 XID 对应的全局事务的管辖;

  4、TM 向 TC 发起针对 XID 的全局提交或回滚决议;

  5、TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

Seata 部署

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

  项目结构图:

    

Seata服务端(TC)部署

  1、下载服务端压缩包,地址:https://github.com/seata/seata/releases

    本例下载的是 seata-server-1.2.0.tar.gz,并解压

  2、修改事务日志存储模式为 db 及数据库连接信息,即修改 conf目录中 flie.conf 文件,如下:

 1 ## transaction log store, only used in seata-server
 2 store {
 3   ## store mode: file、db
 4   mode = "db"
 5 
 6   ## file store property
 7   file {
 8     ## store location dir
 9     dir = "sessionStore"
10     # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
11     maxBranchSessionSize = 16384
12     # globe session size , if exceeded throws exceptions
13     maxGlobalSessionSize = 512
14     # file buffer size , if exceeded allocate new buffer
15     fileWriteBufferCacheSize = 16384
16     # when recover batch read size
17     sessionReloadReadSize = 100
18     # async, sync
19     flushDiskMode = async
20   }
21 
22   ## database store property
23   db {
24     ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
25     datasource = "druid"
26     ## mysql/oracle/postgresql/h2/oceanbase etc.
27     dbType = "mysql"
28     driverClassName = "com.mysql.cj.jdbc.Driver"
29     url = "jdbc:mysql://localhost:3306/seata"
30     user = "admin"
31     password = "123456"
32     minConn = 5
33     maxConn = 30
34     globalTable = "global_table"
35     branchTable = "branch_table"
36     lockTable = "lock_table"
37     queryLimit = 100
38     maxWait = 5000
39   }
40 }

    由于我们使用了db模式存储事务日志,所以我们需要创建一个seat数据库,建表sql在seat项目的github找到,

    地址:https://github.com/seata/seata/tree/1.2.0/script/server/db 目录 mysql.sql 中

 1 -- -------------------------------- The script used when storeMode is \'db\' --------------------------------
 2 -- the table to store GlobalSession data
 3 CREATE TABLE IF NOT EXISTS `global_table`
 4 (
 5     `xid`                       VARCHAR(128) NOT NULL,
 6     `transaction_id`            BIGINT,
 7     `status`                    TINYINT      NOT NULL,
 8     `application_id`            VARCHAR(32),
 9     `transaction_service_group` VARCHAR(32),
10     `transaction_name`          VARCHAR(128),
11     `timeout`                   INT,
12     `begin_time`                BIGINT,
13     `application_data`          VARCHAR(2000),
14     `gmt_create`                DATETIME,
15     `gmt_modified`              DATETIME,
16     PRIMARY KEY (`xid`),
17     KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
18     KEY `idx_transaction_id` (`transaction_id`)
19 ) ENGINE = InnoDB
20   DEFAULT CHARSET = utf8;
21 
22 -- the table to store BranchSession data
23 CREATE TABLE IF NOT EXISTS `branch_table`
24 (
25     `branch_id`         BIGINT       NOT NULL,
26     `xid`               VARCHAR(128) NOT NULL,
27     `transaction_id`    BIGINT,
28     `resource_group_id` VARCHAR(32),
29     `resource_id`       VARCHAR(256),
30     `branch_type`       VARCHAR(8),
31     `status`            TINYINT,
32     `client_id`         VARCHAR(64),
33     `application_data`  VARCHAR(2000),
34     `gmt_create`        DATETIME(6),
35     `gmt_modified`      DATETIME(6),
36     PRIMARY KEY (`branch_id`),
37     KEY `idx_xid` (`xid`)
38 ) ENGINE = InnoDB
39   DEFAULT CHARSET = utf8;
40 
41 -- the table to store lock data
42 CREATE TABLE IF NOT EXISTS `lock_table`
43 (
44     `row_key`        VARCHAR(128) NOT NULL,
45     `xid`            VARCHAR(96),
46     `transaction_id` BIGINT,
47     `branch_id`      BIGINT       NOT NULL,
48     `resource_id`    VARCHAR(256),
49     `table_name`     VARCHAR(32),
50     `pk`             VARCHAR(36),
51     `gmt_create`     DATETIME,
52     `gmt_modified`   DATETIME,
53     PRIMARY KEY (`row_key`),
54     KEY `idx_branch_id` (`branch_id`)
55 ) ENGINE = InnoDB
56   DEFAULT CHARSET = utf8;
mysql.sql

    

  3、修改注册中心,使用nacos作为注册中心,即修改 conf目录中 registry.conf 文件,如下:

 1 registry {
 2   # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
 3   type = "nacos"
 4 
 5   nacos {
 6     application = "seata-server"
 7     serverAddr = "localhost:8848"
 8     namespace = ""
 9     cluster = "default"
10     username = ""
11     password = ""
12   }
13 }

  4、启动Nacos服务(参考:【SpringCloud】Spring Cloud Alibaba 之 Nacos注册中心(二十七))、在启动Seata服务

    Seata服务启动命令:sh ./bin/seata-server.sh    

    

Seata客户端(TM和RM)部署

业务数据库准备

  订单库order

 1 CREATE DATABASE seata_order;
 2 
 3 USE seata_order;
 4 
 5 CREATE TABLE `order` (
 6   `id` bigint(11) NOT NULL AUTO_INCREMENT,
 7   `user_id` bigint(11) DEFAULT NULL COMMENT \'用户id\',
 8   `product_id` bigint(11) DEFAULT NULL COMMENT \'产品id\',
 9   `count` int(11) DEFAULT NULL COMMENT \'数量\',
10   `money` decimal(11,0) DEFAULT NULL COMMENT \'金额\',
11   `status` int(1) DEFAULT NULL COMMENT \'订单状态:0:创建中;1:已完结\',
12   PRIMARY KEY (`id`)
13 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

  库存库storage

 1 USE seata_storage;
 2 
 3 CREATE TABLE `storage` (
 4                          `id` bigint(11) NOT NULL AUTO_INCREMENT,
 5                          `product_id` bigint(11) DEFAULT NULL COMMENT \'产品id\',
 6                          `total` int(11) DEFAULT NULL COMMENT \'总库存\',
 7                          `used` int(11) DEFAULT NULL COMMENT \'已用库存\',
 8                          `residue` int(11) DEFAULT NULL COMMENT \'剩余库存\',
 9                          PRIMARY KEY (`id`)
10 ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
11 
12 INSERT INTO `seata_storage`.`storage` (`id`, `product_id`, `total`, `used`, `residue`) VALUES (\'1\', \'1\', \'100\', \'0\', \'100\');

  账户库

 1 CREATE DATABASE seata_account;
 2 
 3 USE seata_account;
 4 
 5 
 6 CREATE TABLE `account` (
 7   `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT \'id\',
 8   `user_id` bigint(11) DEFAULT NULL COMMENT \'用户id\',
 9   `total` decimal(10,0) DEFAULT NULL COMMENT \'总额度\',
10   `used` decimal(10,0) DEFAULT NULL COMMENT \'已用余额\',
11   `residue` decimal(10,0) DEFAULT \'0\' COMMENT \'剩余可用额度\',
12   PRIMARY KEY (`id`)
13 ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
14 
15 INSERT INTO `seata_account`.`account` (`id`, `user_id`, `total`, `used`, `residue`) VALUES (\'1\', \'1\', \'1000\', \'0\', \'1000\');

  在三个库中都插入undo_log表,sql地址:https://github.com/seata/seata/blob/develop/script/client/at/db/mysql.sql

 1 -- for AT mode you must to init this sql for you business database. the seata server not need it.
 2 CREATE TABLE IF NOT EXISTS `undo_log`
 3 (
 4     `branch_id`     BIGINT(20)   NOT NULL COMMENT \'branch transaction id\',
 5     `xid`           VARCHAR(100) NOT NULL COMMENT \'global transaction id\',
 6     `context`       VARCHAR(128) NOT NULL COMMENT \'undo_log context,such as serialization\',
 7     `rollback_info` LONGBLOB     NOT NULL COMMENT \'rollback info\',
 8     `log_status`    INT(11)      NOT NULL COMMENT \'0:normal status,1:defense status\',
 9     `log_created`   DATETIME(6)  NOT NULL COMMENT \'create datetime\',
10     `log_modified`  DATETIME(6)  NOT NULL COMMENT \'modify datetime\',
11     UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
12 ) ENGINE = InnoDB
13   AUTO_INCREMENT = 1
14   DEFAULT CHARSET = utf8 COMMENT =\'AT transaction mode undo table\';

  三个数据库

    

Order订单服务

  1、新建订单模块(springcloud-seata-order9011)

    

  2、编辑pom文件,完整pom如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <parent>
 6         <artifactId>test-springcloud</artifactId>
 7         <groupId>com.test</groupId>
 8         <version>1.0-SNAPSHOT</version>
 9     </parent>
10     <modelVersion>4.0.0</modelVersion>
11 
12     <artifactId>springcloud-seata-order9011</artifactId>
13 
14     <dependencies>
15 
16         <!-- seata-->
17         <dependency>
18             <groupId>com.alibaba.cloud</groupId>
19             <artifactId>spring-cloud-alibaba-seata</artifactId>
20             <exclusions>
21                 <exclusion>
22                     <groupId>io.seata</groupId>
23                     <artifactId>seata-all</artifactId>
24                 </exclusion>
25             </exclusions>
26         </dependency>
27         <dependency>
28             <groupId>io.seata</groupId>
29             <artifactId>seata-all</artifactId>
30             <version>1.2.0</version>
31         </dependency>
32 
33         <!-- alibaba nacos discovery -->
34         <dependency>
35             <groupId>com.alibaba.cloud</groupId>
36             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
37         </dependency>
38 
39         <dependency>
40             <groupId>org.springframework.cloud</groupId>
41             <artifactId>spring-cloud-starter-openfeign</artifactId>
42         </dependency>
43 
44         <!-- spring boot -->
45         <dependency>
46             <groupId>org.springframework.boot</groupId>
47             <artifactId>spring-boot-starter-web</artifactId>
48         </dependency>
49         <dependency>
50             <groupId>org.springframework.boot</groupId>
51             <artifactId>spring-boot-starter-actuator</artifactId>
52         </dependency>
53         <dependency>
54             <groupId>org.springframework.boot</groupId>
55             <artifactId>spring-boot-devtools</artifactId>
56             <scope>runtime</scope>
57             <optional>true</optional>
58         </dependency>
59 
60         <dependency>
61             <groupId>org.springframework.boot</groupId>
62             <artifactId>spring-boot-starter-jdbc</artifactId>
63         </dependency>
64 
65         <dependency>
66             <groupId>org.mybatis.spring.boot</groupId>
67             <artifactId>mybatis-spring-boot-starter</artifa

以上是关于SpringCloudSpring Cloud Alibaba 之 Seata 分布式事务中间件(三十五)的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloudSpring Cloud Config 配置中心(二十)

SpringCloudSpring Cloud Config 客户端(二十一)

SpringCloudSpring Cloud Alibaba 及 Nacos介绍(二十六)

SpringCloudSpring Cloud Alibaba 之 Nacos配置中心(二十八)

SpringCloudSpring Cloud Bus 服务总线(二十二)

SpringCloudSpring Cloud Alibaba 之 Sentinel熔断降级(三十一)