1. Seata是什么?
Seata 是一款开源的分布式事务
解决方案,致力于提供高性能
和简单易用
的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和XA 事务模式,为用户打造一站式的分布式解决方案。AT模式
是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)。
2. Seata的三大角色
在 Seata 的架构中,一共有三个角色:
- TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。 - TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。 - RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。
3. AT 模式介绍
AT 模式是一种无侵入
的分布式事务解决方案。阿里 Seata
框架,实现了该模式。
在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。
3.1 AT模式实现说明
-
一阶段:
- Seata 会拦截" 业务SQL",
解析
SQL 语义 - 查询 “业务SQL” 要更新的业务数据,在业务数据被更新前,将其保存成 “
before image
” 执行
“业务SQL” ,更新业务数据- 查询更新后的数据,将其保存成 “
after image
” - 将 before image 和 after image 保存至
Undo Log
表中 - 生成行锁
以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
- Seata 会拦截" 业务SQL",
-
二阶段(提交):
- 因为 “业务SQL” 在一阶段已经提交至数据库,所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。
- 因为 “业务SQL” 在一阶段已经提交至数据库,所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。
-
二阶段(回滚):
- 首先要校验脏写,对比“数据库当前业务数据”和 “after image”
- 如果两份数据完全一致就说明没有脏写,可以还原业务数据。
- 如果不一致就说明有脏写,出现脏写就需要转人工处理。
- 用“before image”还原业务数据
- 删除快照数据和行锁
- 首先要校验脏写,对比“数据库当前业务数据”和 “after image”
3.2 实例说明
下单操作中包含 对订单服务与库存服务的操作,分别修改订单状态,与库存数量。示例图如下:
4. 设计亮点
相比与其它分布式事务框架,Seata架构的亮点主要有几个:
- 应用层基于SQL解析实现了自动补偿,从而最大程度的降低业务侵入性;
- 将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚;
- 通过全局锁实现了写隔离与读隔离。
5. Seata 快速开始
5.1 Seata Server(TC)环境搭建
5.1.1 下载安装包
链接: https://github.com/seata/seata/releases
注意:选择的 Seata 版本最好要与 Spring Cloud 版本相匹配
链接: spring-cloud-alibaba 版本说明文档
本文使用 Windos环境下的 seata-server-1.3.0 进行部署说明:
5.1.2 事务信息存储配置
Server 端存储模式(store.mode)支持三种方式:
- file:单机模式(默认为此模式),全局事务会话信息存储在内存中,读写并持久化至本地文件 root.data (bin\sessionStore\root.data) 中,性能较高。
- db:
高可用模式
(Mysql 5.7+),全局事务会话信息通过db共享,相应性能差些。 - redis:Seata-Server 1.3及以上版本支持,性能较高,但存在事务信息丢失风险,请提前配置适合当前场景的redis持久化配置。
本文选用 db
模式进行配置说明:
- 打开
conf/file.conf
文件 - 修改 mode = “db”
- 修改数据库连接信息(url\user\password),如下图所示:
- 创建数据库 seata-server
- 新建表:可以去seata提供的资源信息中下载:
- 官网:点击查看(或根据版本分支选择对应的资源目录)
client:存放 client 端 sql 脚本,参数配置
config-center:各个配置中心参数导入脚本,其中 config.txt (包含server和client)为通用参数文件
server:server 端数据库脚本及各个容器配置
- 官网:点击查看(或根据版本分支选择对应的资源目录)
后续配置中会用到
config-center/config.txt
与config-center/nacos/nacos-config.sh
两个文件,可以选择直接复制其内容并定义相同名称,也可把script 文件夹下载下来。
- 运行 server\db\mysql.sql 文件:
global_table:存储全局事务的信息
branch_table:存储事务参与者的信息
lock_table:存储锁信息(锁的表信息,行信息)
5.1.3 Nacos(注册&配置中心)配置
- 将Seata Server注册到Nacos,并配置到配置中心
打开conf/registry.conf
,修改conf目录下的registry.conf配置:
注意:如果配置了seata server使用nacos作为配置中心,则配置信息会从nacos读取,file.conf可以不用配置。 客户端配置registry.conf
使用nacos时也要注意group要和seata server中的group一致,默认group是"DEFAULT_GROUP"
-
启动注册中心 Nacos Server
Nacos 单机或集群模式下都可以:- 单机模式:后续的配置默认 seata 连接 nacos 端口为 8848;
- 集群模式:以 nginx 配置的端口为准,本文使用的端口为 8847;
-
配置Nacos 配置中心
获取/seata/script/config-center/config.txt 文件,修改配置信息,如下图:- 修改数据库相关配置
- 配置事务分组
service.vgroupMapping.my_test_tx_group=default
- my_test_tx_group:需要与客户端保持一致 ,可以自定义(projectA、projectB…)
(客户端properties配置:spring.cloud.alibaba.seata.tx‐service‐group=my_test_tx_group) - default:需要跟客户端和registry.conf中registry中的cluster保持一致 (即5.1.3的第一步配置)
default 必须要等于 registry.conf cluster = “default”
事务分组主要可以解决:异地机房停电问题,提高容错
- 修改数据库相关配置
5.1.4 Seata 配置文件注册至 Nacos 配置中心
- 下载
Git
,Windows 环境需有此工具,才可运行.sh
文件,安装成功如下图:
- 获取 /seata/script/config-center/nacos/nacos-config.sh 文件:考虑到用户复制文件与直接下载 script 文件夹 两种情况
- 直接复制文件使用,如下图:
注意!!!
需要修改 nacos-config.sh 文件 86 行代码,用以获取 config.txt 文件。
- 下载整个 script 文件夹,复制到 bin 同级目录下,无需修改 nacos-config.sh 文件,如下图:
- 直接复制文件使用,如下图:
- 运行 nacos-config.sh
// 运行指令 ,通过 Git Bash Here
sh nacos‐config.sh ‐h localhost ‐p 8848 -u nacos -w nacos ‐g SEATA_GROUP ‐t 5a3c7d6c‐f497‐4d68‐a71a‐2e5e3340b3ca
参数说明:
-h: host,默认值 localhost
-p: port,默认值 8848
-u: nacos用户名
-w: nacos密码
-g: 配置分组,默认值为 ‘SEATA_GROUP’
-t: 租户信息,对应 Nacos 的命名空间ID字段, 默认值为空 ‘’
成功结果如下图所示:
5.1.5 启动 Seata Server
- 单体环境:双击
seata-server.bat
即可
启动成功,默认端口 8091,如下图所示:
- 集群环境:命令启动,需在 Linux 环境下
bin/seata-server.sh -h 127.0.0.1 -p 8091 -m db -n 1 -e test
启动参数说明:
参数 | 全写 | 作用 | 备注 |
---|---|---|---|
-h | –host | 指定在注册中注册的IP | 不指定时获取当前的IP,外部访问部署在云环境和容器中的server,建议指定 |
-p | –port | 指定server 启动的端口 | 默认为8091 |
-m | –storeMode | 事务日志存储方式 | 支持 file,db,redis,默认为file。注:redis需 seata-server 1.3 版本及以上 |
-n | –serverNode | 用于指定seata-server节点ID | 如 1,2,3 … ,默认为 1 |
-e | –seataEnv | 指定seata-server运行环境 | 如 dev,test 等,服务启动时会使用 registry-dev.conf 这样的配置 |
bin/seata-server.sh -p 8091 -n 1
bin/seata-server.sh -p 8092 -n 2
bin/seata-server.sh -p 8093 -n 3
5.2 Seata Client 代码实现
声明式事务实现添加(@GlobalTransactional)
接入微服务应用
业务场景:
用户下单,整个业务逻辑由三个微服务构成,如下图所示:
订单服务:根据采购需求创建订单。
库存服务:对给定的商品扣除库存数量
5.2.1 启动Seata server端,Seata server使用nacos作为配置中心和注册中心(上一步已完成)
5.2.2 配置微服务整合seata
- 添加pom 依赖
<dependencies>
<!--nacos 服务注册与发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--导入openfeign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!-- skywalking 工具类 可自定义链路追踪,跟服务版本一致-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.12.0</version>
</dependency>
</dependencies>
- 在各微服务对应数据库中添加 undo_log 表
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
- 修改application.yml配置
- 添加事务分组
tx-service-group: my_test_tx_group
详情说明:
参考 5.1.3 Nacos(注册&配置中心)配置 ---->配置Nacos 配置中心-----> 配置事务分组 说明
my_test_tx_group:需要与客户端保持一致 ,可以自定义(projectA、projectB…)
(客户端properties配置:spring.cloud.alibaba.seata.tx‐service‐group=my_test_tx_group)
- 配置 seata 的注册中心, 告诉 seata client 怎么去访问 seata server 事务协调者进行通信
- 配置 seata 的配置中心,可以读取关于 seata client 的一些配置,即 “seata\seata\script\config-center\config.txt” 中的配置
具体yaml 配置如下:
spring:
application:
name: seata-order
datasource:
url: jdbc:mysql://172.16.10.132:3306/seata_order?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
server-addr: 172.16.10.132:8847 # 此处通过 nginx进行通信
discovery:
username: nacos
password: nacos
alibaba:
seata:
tx-service-group: my_test_tx_group # 配置事务分组,在 "seata\seata\script\config-center\config.txt" 中设置
server:
port: 8070
seata:
registry: # 注册中心
# 配置 seata 的注册中心, 告诉 seata client 怎么去访问 seata server 事务协调者进行通信
type: nacos
nacos:
server-addr: 172.16.10.132:8847 # seata-server 所在的注册中心地址
application: seata-server # 指定 seata-server 在注册中心的 服务名, (默认 seata-server)
username: nacos
password: nacos
group: SEATA_GROUP # 默认 SEATA_GROUP
config:
# 配置 seata 的配置中心,可以读取关于 seata client 的一些配置,即 "seata\seata\script\config-center\config.txt" 中的配置
type: nacos
nacos: # 配置中心
server-addr: 172.16.10.132:8847
username: nacos
password: nacos
group: SEATA_GROUP
- 在启动类或方法上添加
@GlobalTransactional
即可
总结
以上步骤都完成后,就实现了 Seata 分布式事务的搭建与使用,希望这篇文章能对你们有所帮助。