第五章 分布式事务Seata
在微服务系统中,分布式事务是我们必须要面临和解决的问题!!!
1. 分布式事务问题的产生
下图中的例子可以很好的解释分布式事务问题出现的场景:
图中问题的产生就在于更新库存数量是1个单独的事务,不受下订单方法所在事务的控制,更新库存数量方法执行之后,数量就已经持久化到数据库,后续的保存订单操作若出现异常也和它无关。这符合事务的隔离性和持久性的特性。事务的另外2个特性:原子性和一致性。
针对上述问题,目前比较主流的技术就是阿里巴巴推出的开源分布式事务解决方案Seata。
2. Seata简介和安装
根据Seata官网的描述:Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
从官网上截取的一个关于Seata如何处理分布式事务的图:
Seata术语解释:
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
通俗理解:统筹协调各个分支事务的全局事务管理者,这个必须要另外启动一个seata的服务端。
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
通俗理解:一般是分布式事务的发起方。需要我们在微服务端进行Seata的配置。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
通俗理解:RM一般是事务的参与者,也就是各个分支事务。需要我们在微服务进行Seata的配置
Seata Client - Seata客户端
每个引入了Seata依赖的微服务都称之为Seata客户端
Seata Server - Seata服务端*
Seata服务端也是一个微服务,需要注册到注册中心(一般是nacos)作为分布式事务的全局管理者,对分布式事务进行协调和处理。
注意:针对于Seata的理论部分,这里不做过多说明,本文只是交给大家如何使用,理论部分可去Seata官网或者去B站看看相关视频即可有一定的理解。
问题:如何使用Seata处理分布式事务问题?
- 使用Seata前,修改Seata下conf文件夹下的相关文件,比如:file.conf,registry.conf;
- 使用数据库(推荐mysql)创建数据库(一般为seata)和表,建表sql一般在Seata的github官网可以找到存储分布式事务相关数据;
- 使用命令将客户端的相关配置(配置文件为config.txt)上传到nacos进行管理;
- 先启动Seata server作为微服务,,并将其注册到注册中心(一般选取nacos作为注册中心);
- 在需要使用分布式事务的微服务引入Seata的依赖,并编写配置文件。启动微服务即可完成Seata的引入。
接下来我们就上述步骤进行细致分解:
以下配置以windows10环境,Seata版本1.3.0,mysql 5.7+,jdk 1.8为准!!!
2.1 下载Seata
这里我们下载2个文件夹
2.1.1 下载配置文件相关文件夹seata-1.3.0
下载地址:https://github.com/seata/seata
将Seata项目以zip压缩包的形式下载。
下载及解压后如下图:
说明:为什么要下载上述文件夹?
因为如果只下载seata-server项目的话,初始化的sql脚本自1.0
版本之后不在随项目提供,另外关于seata的客户端配置也没有提供。缺失的文件都在上面下载的文件夹的script
目录中,因此我们有必要将其下载。
我们主要使用script,这里主要介绍script文件夹下的内容:
2. Seata server微服务seata
下载
下载地址:https://github.com/seata/seata/releases
下载之后解压:
由于启动seta-server端服务需要提前配置或修改一些配置文件,比如要上传到nacos的seata客户端的配置,seata数据库的建表语句等。因此我们才在2.1.1中将这些文件事先下载。
2.2 数据库准备
在mysql数据库中创建一个数据库seata
:
使用数据库管理工具执行目录C:\software\seata-1.3.0\script\server\db
(不同电脑存放路径不同)下的mysql.sql
sql文件。
这样的话,Seata相关的数据库和表就准备好了。
注意:如果数据库的名称不是seata,那么后面对应的配置文件中关于数据库的连接的配置也要对应修改!
2.3 修改seata配置文件(重点)
由于seata服务端的默认配置是以file文件的形式存储分布式事务中的信息的 。我们想要以数据库的存储方式来替换掉,因此需要修改相关配置文件。
打开目录C:\software\seata\conf
(不同电脑存放路径不同):
2.3.1 修改file.conf文件
2.3.2 修改registry.conf文件
2.4 上传客户端配置到注册中心nacos(重点)
在2.3.2中我们配置了连接nacos配置中心,要将seata关于客户端的配置上传到nacos配置中心,那么配置文件呢?需不需要修改呢?
打开目录C:\software\seata-1.3.0\script\config-center
(不同电脑存放路径不同):
config.txt
中的内容都是以键值对的形式存储的seata关于客户端的配置信息。在1.0
版本之前键以-
隔开每个单词如:vgroup-mapping
,1.0
的版本以驼峰命名法命名如:vgroupMapping
。修改文件config.txt
:
更正:上图中的.yml/yalm/application 更改为:yml/yaml/properties!!!
接下来我们使用命令将config.txt
中的配置上传到nacos配置中心。打开目录C:\software\seata-1.3.0\script\config-center\nacos
(不同电脑存放路径不同):
.sh
结尾的文件是linux脚本命令,这里我们使用的windows系统,需要安装git
才可以执行该命令。
git
下载地址:https://git-scm.com/downloads
在·nacos-config.sh·所在目录打开git
命令窗口,执行以下命令:
参数说明:
-h
nacos所在主机地址。如:127.0.0.1;
-p
nacos端口号。如:8848;
-t
命名空间。如:ae5104ef-bb91-467f-b1f4-c93f3b4ab326。
-g
分组组名。 如:DEFAULT_GROUP;
可根据需要进行添加。添加前要对照registry.conf
中关于config
下的配置,要和里面的配置保持一致。否则配置信息上传到不同的命名空间和分组,会导致后面使用seata客户端拉取不到对应的配置信息。
执行命令后,若出现以下内容:
表明配置信息已经上传到nacos
配置中心,此时可以查看nacos
界面:
2.5 启动seata服务
启动客户端很简单。进入目录C:\software\seata\bin
(不同电脑路径不同):
在该目录打开cmd
命令窗口win+R
输入以下内容:
出现以下内容:
seata服务端启动成功,默认端口8091。此时查看nacos
的服务:
2.6 配置Seata客户端
2.6.1 引入Seata依赖
本次引入的seata的版本是1.3.0
。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<!--spring-cloud-starter-alibaba-seata引入的Seata引入的版本与我们使用的seata版本不一样,故将其排除-->
<exclusions>
<exclusion>
<artifactId>seata-spring-boot-starter</artifactId>
<groupId>io.seata</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入我们指定的Seata版本-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
2.6.2 编写配置文件
在使用分布式事务的微服务端的配置文件.yml/.yaml/.properties
中配置如下:
spring:
cloud:
alibaba:
seata:
# 自定义事务组的名称:这里自定的事务组名称为xgwms_inventory_tx_group
tx-service-group: xgwms_inventory_tx_group
seata:
enabled: true
# 哪个微服务要使用分布式事务
application-id: ${spring.application.name}
# 分布式事务组组名
tx-service-group: xgwms_inventory_tx_group
enable-auto-data-source-proxy: true
registry:
type: nacos
nacos:
application: seata-server
# nacos注册中心地址
server-addr: 120.26.0.43:8848
# 注册到哪个命名空间,默认为public
namespace: ae5104ef-bb91-467f-b1f4-c93f3b4ab326
# nacos服务所在分组组名
group: DEFAULT_GROUP
username: nacos
password: nacos
config:
type: nacos
nacos:
# namcos配置中心地址
serverAddr: 120.26.0.43:8848
# 哪个命名空间的配置,默认为public
namespace: ae5104ef-bb91-467f-b1f4-c93f3b4ab326
# nacos客户但配置所在分组组名
group: DEFAULT_GROUP
username: nacos
password: nacos
service:
vgroup-mapping:
xgwms_inventory_tx_group: default
以上只是关于seata分布式事务的配置,其它配置省略。启动配置好seata的微服务,控制台结果如下:
2.6.3 Seata的使用
在要使用分布式事务的入口方法上添加注解@GlobalTransaction
即可实现分布式事务的控制。比如:
3 Seata安装遇到的问题及解决办法
3.1 Seata启动后,在nacos显示的ip不是真实的服务器ip
场景描述:我把seata部署到了自己购买的一台阿里云服务器上(例如IP为120.26.0.43),使用命令seata-server.bat
启动之后,登录到nacos查看,发现seata的ip和阿里云服务器实际ip不同,是一个内网地址,此时又启动了seata客户端,控制台报错,该怎办?
客户端报错:
可是我的服务器地址明明是120.26.0.43,为什么启动之后变成了172.25.60.251?
解决办法:启动seata-server的时候带上参数:seata-server.bat -h 120.26.0.43
此时,seata客户端就可以正常启动了。
3.2 An exceptionCaught() envent was fired…异常
我们在停止一个seat客户端后,发现seat-server后台报错,且乱码:
出现了异常:
这个错误是由非正常Seata客户端建立连接引起(如通过http访问Seata server的端口,云服务器的端口扫描等)。这种连接没有发送注册信息,被认为是无用连接,该异常可以忽视。
乱码解决:
打开cmd
窗口,输入:chcp 65001
意思是设置当前窗口使用UTF-8
编码。在该窗口启动seata-server服务,就不会出现乱码了。注意:该方法只能临时设置cmd
窗口编码方式,若另开一个cmd
窗口,则编码依然是GBK
。