Springcloud基础知识(17)- Spring Cloud Alibaba Seata (三) | 配置 db 存储模式、整合 Nacos


本文使用 “Springcloud基础知识(15)- Spring Cloud Alibaba Seata (一) | Seata 简介、事务模式、Seata Server” 里的 Seata Server 1.4.2,演示整合 Nacos 后如何使用事务分组。

1. 配置 db 存储模式

    在 Seata Server 的 conf/file.conf 文件里,可以看到 store.mode 的三种存储模式:

模式 描述
file 文件存储模式,默认存储模式;该模式为单机模式,全局事务的会话信息在内存中读写,并持久化本地文件 root.data,性能较高。
db 数据库存储模式;该模式为高可用模式,全局事务会话信息通过数据库共享,性能较低。建数据库表
redis 缓存模式;Seata Server 1.3 及以上版本支持该模式,性能较高,但存在事务信息丢失风险,    配置 redis 持久化配置

 

    1) 创建数据库并初始化表

        在 MariaDB (MySQL) 中,创建一个名为 seata 的数据库实例,并在该数据库内执行以下 SQL。

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

 

    2) 修改 conf/file.conf 文件

 1         ## transaction log store, only used in seata-server
 2         store {
 3             ## store mode: file、db、redis
 4             mode = "db"
 5 
 6             ...
 7 
 8             ## database store property
 9             db {
10                 ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
11                 datasource = "druid"
12                 ## mysql/oracle/postgresql/h2/oceanbase etc.
13                 dbType = "mysql"
14                 driverClassName = "com.mysql.jdbc.Driver"
15                 ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
16                 url = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true"
17                 user = "root"
18                 password = "123456"
19                 minConn = 5
20                 maxConn = 100
21                 globalTable = "global_table"
22                 branchTable = "branch_table"
23                 lockTable = "lock_table"
24                 queryLimit = 100
25                 maxWait = 5000
26             }
27 
28             ...
29         }


 

2. 整合 Nacos

    本文使用 “Springcloud基础知识(11)- Spring Cloud Alibaba Nacos (一) | Nacos 简介、服务注册中心” 里的 Nacos 2.1.0 作为 Seata 的注册和配置中心。


    1) 修改 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 = "127.0.0.1:8848"
 8                 group = "SEATA_GROUP"
 9                 namespace = ""
10                 cluster = "default"
11                 username = "nacos"
12                 password = "nacos"
13             }
14 
15             ...
16         }
17 
18         config {
19             # file、nacos 、apollo、zk、consul、etcd3
20             type = "nacos"
21 
22             nacos {
23                 serverAddr = "127.0.0.1:8848"
24                 namespace = ""
25                 group = "SEATA_GROUP"
26                 username = "nacos"
27                 password = "nacos"
28                 dataId = "seataServer.properties"
29             }
30 
31             ...
32 
33         }


        注:设置 type = "nacos" 后,Seata Server 就无法读取 conf/file.conf 里的 db 配置,此时需要把 db 配置部署到 Nacos 配置中心。      


    2) 在 Nacos 上创建配置

        (1) 访问 Nacos 页面创建单个 dataId 配置

            从 Seata Server 1.4.2 版本开始,已支持从一个 Nacos dataId 中获取所有配置信息,只需在 Nacos 配置中心添加一个配置项。

            浏览器访问 http://localhost:8848/nacos/, 输入登录名和密码(默认 nacos/nacos),点击提交按钮,跳转到 Nacos Server 控制台页面。

            在 Nacos Server 控制台的 “配置管理” 下的 “配置列表” 中,点击 “+” 按钮,新建如下配置。

 1                 Data ID: seataServer.properties
 2                 Group:   SEATA_GROUP
 3                 配置格式: Properties
 4                 配置内容:
 5 
 6                     # 将 Seata Server 的存储模式修改为 db
 7                     store.mode=db
 8                     store.lock.mode=db
 9                     store.session.mode=db
10                     store.db.datasource=druid
11                     store.db.dbType=mysql
12                     store.db.driverClassName=com.mysql.cj.jdbc.Driver
13                     store.db.url=jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true14                     store.db.user=nacos
15                     store.db.password=nacos
16                     store.db.minConn=5
17                     store.db.maxConn=30
18                     store.db.globalTable=global_table
19                     store.db.branchTable=branch_table
20                     store.db.lockTable=lock_table
21                     store.db.queryLimit=100
22                     store.db.maxWait=5000


                注:配置内容参考 https://github.com/seata/seata/tree/develop/script/config-center/config.txt,根据项目需要添加到 “配置内容” 栏。

        (2) 使用脚本上传多个 dataId 配置

            可以下载 https://github.com/seata/seata/tree/develop/script/config-center 目录的文件到本地,该目录包含了 nacos 脚本和 config.txt。

            本文直接下载 https://github.com/seata/seata/archive/refs/tags/v1.4.2.zip,解压后把目录中的整个 script 目录复制到本地 Seata Server 的安装目录。

            Nacos 脚本 Shell 命令:

                $ cd ${SEATAPATH}/script/config-center/nacos/
                $ sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t '' -u nacos -w nacos

                参数说明:

                    -h: Nacos 主机,默认 localhost。
                    -p: Nacos 端口,默认 8848。
                    -g: Nacos 配置组,默认 'SEATA_GROUP'。
                    -t: 租户信息,等同于 Nacos 命名空间 ID,默认 '' (public 空间)。
                    -u: Nacos 用户名,默认 ''。
                    -w: Nacos 密码,默认 ''。

            以上命令会自动读取 config-center/config.txt 文件里的配置,每一行配置在 nacos 配置中心产生一个  dataId。建议在原目录下,新建一个config.txt,根据项目需要添加配置项。

        注:在 Seata Server 1.4.2 及以上版本,以上两种配置方式都可以使用。如果使用多个 dataId 配置时,要把 conf/registry.conf 里的 config.nacos.dataId 项注释掉。


    3) 重启 Seata Server

        C:\seata-server-1.4.2\bin>seata-server -p 8092

1         ...
2 
3         SLF4J: A number (18) of logging calls during the initialization phase have been intercepted and are
4         SLF4J: now being replayed. These are subject to the filtering rules of the underlying logging system.
5         SLF4J: See also http://www.slf4j.org/codes.html#replay
6         17:30:52.993  INFO --- [                     main] io.seata.config.FileConfiguration        : The file name of the operation is registry
7         17:30:52.997  INFO --- [                     main] io.seata.config.FileConfiguration        : The configuration file used is C:\Applications\Java\alibaba-cloud\seata-server-1.4.2\conf\registry.conf
8         17:30:54.166  INFO --- [                     main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
9         17:30:54.588  INFO --- [                     main] i.s.core.rpc.netty.NettyServerBootstrap  : Server started, listen port: 8092


3. 创建 Seata 客户端

    本文在 “ Springcloud基础知识(16)- Spring Cloud Alibaba Seata (二) | 事务分组 ” 里 SpringcloudDemo05 项目基础上,创建 SeataNacosClient 子模块。


    1) 创建 SeataNacosClient 子模块

        选择左上的项目列表中的 SpringcloudDemo05,点击鼠标右键,选择 New -> Module 进入 New Module 页面:

            Maven -> Project SDK: 1.8 -> Check "Create from archtype" -> select "org.apache.maven.archtypes:maven-archtype-quickstart" -> Next

                Name: SeataNacosClient
                GroupId: com.example
                ArtifactId: SeataNacosClient

            -> Finish

    2) 修改 pom.xml,内容如下

 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
 5                                     http://maven.apache.org/xsd/maven-4.0.0.xsd">
 6             <parent>
 7                 <artifactId>SpringcloudDemo05</artifactId>
 8                 <groupId>com.example</groupId>
 9                 <version>1.0-SNAPSHOT</version>
10             </parent>
11             <modelVersion>4.0.0</modelVersion>
12 
13             <artifactId>SeataNacosClient</artifactId>
14 
15             <name>SeataNacosClient</name>
16             <!-- FIXME change it to the project's website -->
17             <url>http://www.example.com</url>
18 
19             <properties>
20                 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21                 <maven.compiler.source>1.8</maven.compiler.source>
22                 <maven.compiler.target>1.8</maven.compiler.target>
23                 <maven.install.skip>true</maven.install.skip>
24             </properties>
25 
26             <dependencies>
27                 <dependency>
28                     <groupId>junit</groupId>
29                     <artifactId>junit</artifactId>
30                     <scope>test</scope>
31                 </dependency>
32 
33                 <dependency>
34                     <groupId>org.springframework.boot</groupId>
35                     <artifactId>spring-boot-starter-web</artifactId>
36                 </dependency>        
37                 <dependency>
38                     <groupId>org.springframework.boot</groupId>
39                     <artifactId>spring-boot-starter-test</artifactId>
40                     <scope>test</scope>
41                 </dependency>
42 
43                 <!-- nacos -->
44                 <dependency>
45                     <groupId>com.alibaba.cloud</groupId>
46                     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
47                 </dependency>
48                 <dependency>
49                     <groupId>com.alibaba.cloud</groupId>
50                     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
51                 </dependency>
52                 <!-- seata -->
53                 <dependency>
54                     <groupId>com.alibaba.cloud</groupId>
55                     <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
56                     <!-- Spring cloud 2021.1 自动导入的 seata 版本是 1.3.0 -->
57                     <exclusions>
58                         <exclusion>
59                             <groupId>io.seata</groupId>
60                             <artifactId>seata-spring-boot-starter</artifactId>
61                         </exclusion>
62                     </exclusions>
63                 </dependency>
64                 <dependency>
65                     <groupId>io.seata</groupId>
66                     <artifactId>seata-spring-boot-starter</artifactId>
67                     <version>1.4.2</version>
68                 </dependency>
69 
70             </dependencies>
71 
72       </project>
73 


        注:这里我们用 seata 1.4.2 版本替换自动导入的 seata 1.3.0 版本,是因为下文需要用到 seata 1.4.2 的导入单个 dataId 配置的功能。

    3) 访问 Nacos 页面创建 seataClient.properties

        浏览器访问 http://localhost:8848/nacos/, 输入登录名和密码(默认 nacos/nacos),点击提交按钮,跳转到 Nacos Server 控制台页面。

        在 Nacos Server 控制台的 “配置管理” 下的 “配置列表” 中,点击 “+” 按钮,新建如下配置。

1             Data ID: seataClient.properties
2             Group:   SEATA_GROUP
3             配置格式: Properties
4             配置内容:
5 
6                 service.vgroupMapping.default_tx_group=default
7                 service.default.grouplist=127.0.0.1:8092


        注:可以把这两条内容直接加入到 seataServer.properties,无需新创建 seataClient.properties。这里分开放置 server 和 client 的配置,可以避免混淆两者的配置。

    4) 创建 src/main/resources/application.yml 文件

 1         server:
 2             port: 4002  # 端口号
 3 
 4         spring:
 5             application:
 6                 name: seata-nacos-client-4002  # 服务名
 7             cloud:
 8                 nacos:
 9                     discovery:
10                         server-addr: 127.0.0.1:8848
11                         namespace:  # 留空表示使用 public
12                         group: SEATA_GROUP
13                         username: nacos
14                         password: nacos
15                     config:
16                         server-addr: ${spring.cloud.nacos.discovery.server-addr}
17                         context-path: /nacos
18                         namespace:   # 留空表示使用 public
19                         username: ${spring.cloud.nacos.discovery.username}
20                         password: ${spring.cloud.nacos.discovery.password}
21 
22         seata:
23             #enabled: true
24             application-id: ${spring.application.name}
25             tx-service-group: default_tx_group
26             registry:
27                 type: nacos
28                 nacos:
29                     server-addr: ${spring.cloud.nacos.discovery.server-addr}
30                     #application: seata-server
31                     group: ${spring.cloud.nacos.discovery.group}
32                     namespace:   # 留空表示使用 public
33                     username: ${spring.cloud.nacos.discovery.username}
34                     password: ${spring.cloud.nacos.discovery.password}
35             config:
36                 type: nacos
37                 nacos:
38                     server-addr:  ${spring.cloud.nacos.discovery.server-addr}
39                     group: ${spring.cloud.nacos.discovery.group}
40                     namespace:
41                     username: ${spring.cloud.nacos.discovery.username}
42                     password: ${spring.cloud.nacos.discovery.password}
43                     dataId: seataClient.properties


        配置说明:

            a) 获取事务分组(服务启动时加载配置): SeataNacosClient 读取 application.yml 里 seata.tx-service-group 的值 “default_tx_group” (默认值,有的版本使用 "my_test_tx_group");

                注:若 application.yml 里没有配置 seata.tx-service-group 项,自动以 spring.application.name的值 + "-seata-service-group" 拼接后的字符串作为分组名。

                    此时 Nacos 上 seataClient.properties 的配置应该如下。

                        service.vgroupMapping.seata-nacos-client-4002-seata-service-group=default
                        service.default.grouplist=127.0.0.1:8092

            b) 查找 TC 集群名 (clusterName): SeataNacosClient 读取 Nacos 上 seataClient.properties 里的配置 service.vgroupMapping.default_tx_group 的值 "default",即 TC 集群名 (clusterName)。

            c) 查询 TC 服务: SeataNacosClient 读取 seata.service.grouplist.default 的值 “127.0.0.1:8092”,即 TC 服务真实地址。

    5) 修改 src/main/java/com/example/App.java 文件

 1         package com.example;
 2 
 3         import org.springframework.boot.SpringApplication;
 4         import org.springframework.boot.autoconfigure.SpringBootApplication;
 5         import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 
 7         @EnableDiscoveryClient
 8         @SpringBootApplication
 9         public class App {
10             public static void main(String[] args) {
11                 SpringApplication.run(App.class, args);
12             }
13         }


    6) 运行 SeataNacosClient  

        菜单 Run -> Edit Configurations (或工具条上选择) —> 进入 Run/Debug Configurations 页面 -> Click "+" add new configuration -> Select "Maven":

            Working directory: SeataNacosClient 所在路径
            Command line: clean spring-boot:run

        -> Apply / OK

        点击 Run "SeataNacosClient [clean, spring-boot:run]" ,控制台输出如下:

1             INFO 21840 --- [           main] com.example.App                          : Started App in 3.316 seconds (JVM running for 3.619)
2             INFO 21840 --- [eoutChecker_2_1] i.s.c.r.netty.NettyClientChannelManager  : will connect to 192.168.0.2:8092
3             INFO 21840 --- [eoutChecker_1_1] i.s.c.r.netty.NettyClientChannelManager  : will connect to 192.168.0.2:8092
4             INFO 21840 --- [eoutChecker_2_1] i.s.core.rpc.netty.NettyPoolableFactory  : NettyPool create channel to transactionRole:RMROLE,address:192.168.0.2:8092,msg:< RegisterRMRequest{resourceIds='null', applicationId='seata-nacos-client-4002', transactionServiceGroup='default_tx_group'} >
5             INFO 21840 --- [eoutChecker_1_1] i.s.core.rpc.netty.NettyPoolableFactory  : NettyPool create channel to transactionRole:TMROLE,address:192.168.0.2:8092,msg:< RegisterTMRequest{applicationId='seata-nacos-client-4002', transactionServiceGroup='default_tx_group'} >
6             INFO 21840 --- [eoutChecker_2_1] i.s.c.rpc.netty.RmNettyRemotingClient    : register RM success. client version:1.4.2, server version:1.4.2,channel:[id: 0xad4ddb2e, L:/192.168.0.2:49737 - R:/192.168.0.2:8092]
7             INFO 21840 --- [eoutChecker_1_1] i.s.c.rpc.netty.TmNettyRemotingClient    : register TM success. client version:1.4.2, server version:1.4.2,channel:[id: 0x513b3417, L:/192.168.0.2:49736 - R:/192.168.0.2:8092]
8             INFO 21840 --- [eoutChecker_2_1] i.s.core.rpc.netty.NettyPoolableFactory  : register success, cost 92 ms, version:1.4.2,role:RMROLE,channel:[id: 0xad4ddb2e, L:/192.168.0.2:49737 - R:/192.168.0.2:8092]
9             INFO 21840 --- [eoutChecker_1_1] i.s.core.rpc.netty.NettyPoolableFactory  : register success, cost 92 ms, version:1.4.2,role:TMROLE,channel:[id: 0x513b3417, L:/192.168.0.2:49736 - R:/192.168.0.2:8092]


        注:使用 spring-cloud-starter-alibaba-seata 或 seata-spring-boot-starter 的 seata 客户端默认是开启状态 (可以设置 seata.enabled=false 来关闭)。


    seata 客户端里包含了一个全局事务扫描器 (GlobalTransactionScanner),seata 客户端运行后(30 秒左右)GlobalTransactionScanner 会调用初始化功能,使用 netty 连接 Seata 服务端。

    从 log 可以看出 SeataNacosClient 成功连接到了 Seata Server (192.168.0.2:8092),192.168.0.2 是本地主机的内网地址。




posted @ 2022-07-29 21:38  垄山小站  阅读(586)  评论(0编辑  收藏  举报