Springcloud基础知识(16)- Spring Cloud Alibaba Seata (二) | 事务分组
1. 简介
事务分组:Seata 的资源逻辑,可以按微服务的需要,在应用程序(客户端)对自行定义事务分组,每组取一个名字。
集群:Seata-Server 服务端一个或多个节点组成的集群 cluster。 应用程序(客户端)使用时需要指定事务逻辑分组与 Seata 服务端集群的映射关系。
事务分组后找到后端 Seata 集群的可能方式:
(1) 应用程序(客户端)中配置了事务分组(GlobalTransactionScanner 构造方法的 txServiceGroup 参数)。若应用程序是 SpringBoot 则通过 seata.tx-service-group 配置
(2) 应用程序(客户端)会通过用户配置的配置中心去寻找 “service.vgroupMapping.[事务分组配置项]”,取得配置项的值就是TC集群的名称。若应用程序是 SpringBoot 则通过 “seata.service.vgroup-mapping.事务分组名=集群名称” 配置
(3) 根据集群名称,程序通过一定的前后缀+集群名称去构造服务名,各配置中心的服务名实现不同(前提是Seata-Server 已经完成服务注册,且 Seata-Server 向注册中心报告 cluster 名与应用程序(客户端)配置的集群名称一致)
(4) 根据服务名,去相应的注册中心去拉取相应服务名的服务列表,获得后端真实的 TC 服务列表(即 Seata-Server 集群节点列表)
事务分组的作用:多了一层获取事务分组到映射集群的配置。事务分组可以作为资源的逻辑隔离单位,出现某集群故障时可以快速 failover,只切换对应分组,可以把故障缩减到服务级别,但前提也是你有足够 server 集群。
本文使用 “Springcloud基础知识(15)- Spring Cloud Alibaba Seata (一) | Seata 简介、事务模式、Seata Server” 里的 Seata Server 1.4.2,演示默认配置 (file) 下如何使用事务分组。
2. Seata Server 的配置
1) Seata Server 端的配置 (conf/registry.conf)
1 registry { 2 # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa 3 type = "file" 4 5 ... 6 7 file { 8 name = "file.conf" 9 } 10 11 } 12 13 config { 14 # file、nacos 、apollo、zk、consul、etcd3 15 type = "file" 16 17 ... 18 19 file { 20 name = "file.conf" 21 } 22 }
2) 启动 Seata Server
使用带参数的命令行方式启动,格式如下:
C:\seata-server-1.4.2\bin>seata-server -p 8092
1 ... 2 3 22:36:41.922 INFO --- [ main] io.seata.config.FileConfiguration : The file name of the operation is registry 4 22:36:41.926 INFO --- [ main] io.seata.config.FileConfiguration : The configuration file used is C:\Applications\Java\alibaba-cloud\seata-server-1.4.2\conf\registry.conf 5 22:36:41.985 INFO --- [ main] io.seata.config.FileConfiguration : The file name of the operation is file.conf 6 22:36:41.985 INFO --- [ main] io.seata.config.FileConfiguration : The configuration file used is C:\Applications\Java\alibaba-cloud\seata-server-1.4.2\conf\file.conf 7 22:36:42.608 INFO --- [ main] i.s.core.rpc.netty.NettyServerBootstrap : Server started, listen port: 8092
3. 创建 Seata 客户端
本文参考 “ Springcould基础知识(1)- 微服务、Spring Cloud 简介、IDEA 创建多模块项目 ” ,创建 SpringcloudDemo05 项目。
1) 创建 Maven 主项目
运行 IDEA,点击菜单 New 创建 Project:
New Project -> Project Type: Maven -> Project SDK: 1.8 -> Uncheck "Create from archtype" -> Next
Name: SpringcloudDemo05
GroupId: com.example
ArtifactId: SpringcloudDemo05
-> Finish
修改 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 <groupId>org.springframework.boot</groupId> 8 <artifactId>spring-boot-starter-parent</artifactId> 9 <version>2.4.2</version> 10 <relativePath/> <!-- lookup parent from repository --> 11 </parent> 12 13 <modelVersion>4.0.0</modelVersion> 14 <packaging>pom</packaging> 15 16 <groupId>com.example</groupId> 17 <artifactId>SpringcloudDemo05</artifactId> 18 <version>1.0-SNAPSHOT</version> 19 20 <properties> 21 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 <maven.compiler.source>1.8</maven.compiler.source> 23 <maven.compiler.target>1.8</maven.compiler.target> 24 <junit.version>4.12</junit.version> 25 <log4j.version>1.2.17</log4j.version> 26 <lombok.version>1.16.18</lombok.version> 27 <mariadb.version>2.7.4</mariadb.version> 28 <mybatis.version>2.2.0</mybatis.version> 29 <spring-cloud.version>2020.0.4</spring-cloud.version> 30 <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version> 31 </properties> 32 33 <dependencyManagement> 34 <dependencies> 35 <!-- Spring Cloud Alibaba 的版本信息 --> 36 <dependency> 37 <groupId>com.alibaba.cloud</groupId> 38 <artifactId>spring-cloud-alibaba-dependencies</artifactId> 39 <version>${spring-cloud-alibaba.version}</version> 40 <type>pom</type> 41 <scope>import</scope> 42 </dependency> 43 <!-- Spring Cloud 的版本信息 --> 44 <dependency> 45 <groupId>org.springframework.cloud</groupId> 46 <artifactId>spring-cloud-dependencies</artifactId> 47 <version>${spring-cloud.version}</version> 48 <type>pom</type> 49 <scope>import</scope> 50 </dependency> 51 </dependencies> 52 </dependencyManagement> 53 54 <build> 55 <plugins> 56 <plugin> 57 <groupId>org.springframework.boot</groupId> 58 <artifactId>spring-boot-maven-plugin</artifactId> 59 <configuration> 60 <mainClass>com.example.App</mainClass> 61 <layout>JAR</layout> 62 </configuration> 63 <executions> 64 <execution> 65 <goals> 66 <goal>repackage</goal> 67 </goals> 68 </execution> 69 </executions> 70 </plugin> 71 </plugins> 72 </build> 73 74 </project>
通过 dependencyManagement 对 Spring Cloud Alibaba 的版本信息进行管理,各子模块在引入 Spring Cloud Alibaba 的组件时不用指定版本号。
2) 创建 SeataClient 子模块
选择左上的项目列表中的 SpringcloudDemo05,点击鼠标右键,选择 New -> Module 进入 New Module 页面:
Maven -> Project SDK: 1.8 -> Check "Create from archtype" -> select "org.apache.maven.archtypes:maven-archtype-quickstart" -> Next
Name: SeataClient
GroupId: com.example
ArtifactId: SeataClient
-> Finish
3) 修改 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>SeataClient</artifactId> 14 15 <name>SeataClient</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 <!-- seata --> 44 <dependency> 45 <groupId>com.alibaba.cloud</groupId> 46 <artifactId>spring-cloud-starter-alibaba-seata</artifactId> 47 </dependency> 48 49 </dependencies> 50 51 </project> 52
4) 创建 src/main/resources/application.yml 文件
1 server: 2 port: 4001 # 端口号 3 4 spring: 5 application: 6 name: seata-client-4001 # 服务名 7 8 seata: 9 #enabled: true 10 application-id: ${spring.application.name} 11 tx-service-group: default_tx_group # 默认值,有的版本使用 my_test_tx_group 12 service: 13 vgroupMapping: # 这里使用 vgroupMapping 和 vgroup-mapping 都可以 14 default_tx_group: default 15 grouplist: 16 default: 127.0.0.1:8092
配置说明:
a) 获取事务分组(服务启动时加载配置): SeataClient 读取 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" 拼接后的字符串作为分组名。
此时 seata 的配置应该如下。
1 seata: 2 #enabled: true 3 application-id: ${spring.application.name} 4 #tx-service-group: default_tx_group # 默认值,有的版本使用 my_test_tx_group 5 service: 6 vgroupMapping: # 这里使用 vgroupMapping 和 vgroup-mapping 都可以 7 seata-client-4001-seata-service-group: default 8 grouplist: 9 default: 127.0.0.1:8092
b) 查找 TC 集群名 (clusterName): SeataClient 读取 seata.service.vgroupMapping.default_tx_group 的值 "default",即 TC 集群名 (clusterName)。
注:这里使用 “vgroupMapping” 和 “vgroup-mapping” 都可以。
c) 查询 TC 服务: SeataClient 读取 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 6 @SpringBootApplication 7 public class App { 8 public static void main(String[] args) { 9 SpringApplication.run(App.class, args); 10 } 11 }
6) 运行 SeataClient
菜单 Run -> Edit Configurations (或工具条上选择) —> 进入 Run/Debug Configurations 页面 -> Click "+" add new configuration -> Select "Maven":
Working directory: SeataClient 所在路径
Command line: clean spring-boot:run
-> Apply / OK
点击 Run "SeataClient [clean, spring-boot:run]" ,控制台输出如下:
1 ... 2 3 INFO 52548 --- [ main] com.example.App : Started App in 1.366 seconds (JVM running for 1.677) 4 INFO 52548 --- [eoutChecker_1_1] i.s.c.r.netty.NettyClientChannelManager : will connect to 127.0.0.1:8092 5 INFO 52548 --- [eoutChecker_1_1] i.s.core.rpc.netty.NettyPoolableFactory : NettyPool create channel to transactionRole:TMROLE,address:127.0.0.1:8092,msg:< RegisterTMRequest{applicationId='seata-client-4001', transactionServiceGroup='default_tx_group'} > 6 INFO 52548 --- [eoutChecker_2_1] i.s.c.r.netty.NettyClientChannelManager : will connect to 127.0.0.1:8092 7 INFO 52548 --- [eoutChecker_2_1] i.s.core.rpc.netty.NettyPoolableFactory : NettyPool create channel to transactionRole:RMROLE,address:127.0.0.1:8092,msg:< RegisterRMRequest{resourceIds='null', applicationId='seata-client-4001', transactionServiceGroup='default_tx_group'} > 8 INFO 52548 --- [eoutChecker_2_1] i.s.c.rpc.netty.RmNettyRemotingClient : register RM success. client version:1.3.0, server version:1.4.2,channel:[id: 0xfb78406b, L:/127.0.0.1:49690 - R:/127.0.0.1:8092] 9 INFO 52548 --- [eoutChecker_1_1] i.s.c.rpc.netty.TmNettyRemotingClient : register TM success. client version:1.3.0, server version:1.4.2,channel:[id: 0xd35a9b4c, L:/127.0.0.1:49691 - R:/127.0.0.1:8092] 10 INFO 52548 --- [eoutChecker_1_1] i.s.core.rpc.netty.NettyPoolableFactory : register success, cost 36 ms, version:1.4.2,role:TMROLE,channel:[id: 0xd35a9b4c, L:/127.0.0.1:49691 - R:/127.0.0.1:8092] 11 INFO 52548 --- [eoutChecker_2_1] i.s.core.rpc.netty.NettyPoolableFactory : register success, cost 36 ms, version:1.4.2,role:RMROLE,channel:[id: 0xfb78406b, L:/127.0.0.1:49690 - R:/127.0.0.1:8092]
注:使用 spring-cloud-starter-alibaba-seata 或 seata-spring-boot-starter 的 seata 客户端默认是开启状态 (可以设置 seata.enabled=false 来关闭)。
seata 客户端里包含了一个全局事务扫描器 (GlobalTransactionScanner),seata 客户端运行后(30 秒左右)GlobalTransactionScanner 会调用初始化功能,使用 netty 连接 Seata 服务端。
从 log 可以看出 SeataClient 成功连接到了 Seata Server (127.0.0.1:8092)。