集中整理 Seata 的全局事务流程、应用模式、TC 服务配置,以及服务端接入的学习步骤。

本篇要点

  • 理解 TC、TM、RM 的职责
  • 比较不同事务模式
  • 核对 TC 部署与客户端配置

**学习提示:**本篇为 Seata 学习与配置笔记,不能仅凭配置示例推断跨服务事务已在生产环境验证;示例口令和密钥已占位。

3 Seata概述

3.1 Seata流程

  • 使用阿里巴巴提供分布式事务框架Seata实现

  • Seata事务管理中有三个重要的角色:

    1、TC (Transaction Coordinator) - **事务协调者:**全局事务决策者。

    2、TM (Transaction Manager) - **事务管理器:**全局事务发起者。

    3、RM (Resource Manager) - **资源管理器:**管理分支(本地)事务。

  • 实现流程:

1、由TM发起开启全局事务到TC服务器

2、TC服务器开启全局事务,会返回xid(本次全局事务的id)

3、各个微服务模块分支事务,在TC服务器进行注册(注册到全局事务里面)

4、各个微服务模块执行业务SQL,把各个模块执行结果报告给TC服务器

5、TC会进行分支事务状态的统计,如果各个分支都成功,TC决定都提交,如果各个分支有任何一个失败的,TC决定都回滚

image-20241119142815683

3.2 Seata应用模式

1、XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入

首先,注册各个分支到TC里面

第二,执行各个分支sql语句,但是sql语句只是执行不提交

第三,各个分支把执行sql语句结果告诉TC,最终由TC决定这些分支要么都提交,要么都不提交

image-20241119144722778

2、AT模式:默认模式,最终一致的分阶段事务模式,无业务侵入

首先,注册各个分支到TC里面

第二,执行各个分支sql语句,执行之前记录当前状态到undolog里面,执行sql语句并提交

第三,各个分支把执行结果告诉TC,最终由TC决定这些分支要么都提交,要么都回滚,回滚使用undolog

3、TCC模式:最终一致的分阶段事务模式,有业务侵入

  • 过程和AT相似的,手动编码实现

4 Seata使用过程

第一步 部署TC服务

  • 下载Seata服务

image-20241119152426454

  • 解压文件,修改配置文件内容

打开config/application.yml文件

image-20241119152537584

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#  Copyright 1999-2019 Seata.io Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

server:
port: 7091

spring:
application:
name: seata-server

logging:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash

console:
user:
username: seata
password: <SEATA_DB_PASSWORD>
seata:
config:
# support: nacos, consul, apollo, zk, etcd3
type: nacos
nacos:
server-addr: 192.168.200.130:8848
namespace:
username:
password:
context-path:
data-id: seataServer.properties
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: 192.168.200.130:8848
namespace:
cluster: default
username:
password:
context-path:
store:
# support: file 、 db 、 redis
mode: file
# server:
# service-port: 8091 #If not configured, the default is '${server.port} + 1000'
security:
secretKey: <SEATA_SECRET_KEY>
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login
  • 在nacos配置中心创建seataServer.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

# 首先应用程序(客户端)中配置了事务分组,若应用程序是SpringBoot则通过配置seata.tx-service-group=[事务分组配置项]
# 事务群组,service.vgroupMapping.[事务分组配置项]=TC集群的名称
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

client.metadataMaxAgeMs=30000
#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.rm.sqlParserType=druid
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h
# You can choose from the following options: fastjson, jackson, gson
tcc.contextJsonParserType=fastjson

#Log rule configuration, for client and server
log.exceptionRate=100

#事务会话信息存储方式
#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
#事务锁信息存储方式
store.lock.mode=db
#事务回话信息存储方式
store.session.mode=db
#Used for password encryption
store.publicKey=

#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100

#存储方式为db
#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://localhost:3306/seata?useUnicode=true&rewriteBatchedStatements=true&useSSL=false
store.db.user=root
store.db.password=<SEATA_DB_PASSWORD>
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.type=pipeline
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.sentinel.sentinelPassword=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100

#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=true
server.enableParallelHandleBranch=false

server.raft.cluster=127.0.0.1:7091,127.0.0.1:7092,127.0.0.1:7093
server.raft.snapshotInterval=600
server.raft.applyBatch=32
server.raft.maxAppendBufferSize=262144
server.raft.maxReplicatorInflightMsgs=256
server.raft.disruptorBufferSize=16384
server.raft.electionTimeoutMs=2000
server.raft.reporterEnabled=false
server.raft.reporterInitialDelay=60
server.raft.serialization=jackson
server.raft.compressor=none
server.raft.sync=true

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
  • 创建名称seata数据库

– 数据库需要手动创建,建表语句里面没有创建数据库语句

— script\server\db\mysql.sql脚本文件

image-20241119153348599

  • 启动seata服务

image-20241119153542454

image-20241119153900864

第二步 微服务在TC注册

  • 第一次登录,做两个操作:添加用户信息 、 初始化账户信息
  • 把service-user 和 service-account进行注册

service-user 和 service-account两个模块做相同事情:

1 引入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--Seata依赖  -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>

<!--使用2.0.0的seata的版本-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
2 修改bootstrap.properties配置文件
1
2
3
4
5
6
7
8
9
10
spring.application.name=service-user
spring.profiles.active=dev
spring.main.allow-bean-definition-overriding=true
spring.cloud.nacos.discovery.server-addr=192.168.200.130:8848
spring.cloud.nacos.config.server-addr=192.168.200.130:8848
spring.cloud.nacos.config.prefix=${spring.application.name}
spring.cloud.nacos.config.file-extension=yaml

spring.cloud.nacos.config.shared-configs[0].data-id=seata-common.yaml
spring.cloud.nacos.config.shared-configs[0].refresh=true
3 nacos配置中心创建配置文件seata-common.yaml

image-20241119154622826

1
2
3
4
5
6
7
8
9
10
11
12
13
14
seata:
# 配置seata-server在nacos注册中心上的信息
registry:
type: nacos
nacos:
namespace:
application: seata-server
server-addr: 192.168.200.130:8848
# 配置事务组的名称,需要和seata服务端的配置保持一致
tx-service-group: default_tx_group
service:
vgroup-mapping:
default_tx_group: default
data-source-proxy-mode: XA # 配置事务管理模式为xa模式

第三步 在具体业务方法上面添加注解

@GlobalTransactional

image-20241119155254529

1
2
3
4
5
6
7
8
9
10
11
@GlobalTransactional
@Override
public void saveUser(UserInfo userInfo) {
this.save(userInfo);
//int i = 1/0;

//初始化账户
//方法一:远程调用 在service-account创建初始化接口
// 在service-user进行远程调用实现
userAccountFeignClient.initUserAccount(userInfo.getId());
}