Seata 是什么
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)
官 网 :https://seata.io/zh-cn/index.html 源码: https://github.com/seata/seata
官方Demo: https://github.com/seata/seata-samples seata版本:v1.4.0
Seata的三大角色
在 Seata 的架构中,一共有三个角色:
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。
在 Seata 中,一个分布式事务的生命周期如下:
TM 请求 TC 开启一个全局事务。TC 会生成一个 XID 作为该全局事务的编号。XID,会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。
当一进入事务方法中就会生成XID , global_table 就是存储的全局事务信息 , 2.RM 请求 TC 将本地事务注册为全局事务的分支事务,通过全局事务的 XID 进行关联。
当运行数据库操作方法,branch_table 存储事务参与者3.TM 请求 TC 告诉 XID 对应的全局事务是进行提交还是回滚。
4.TC 驱动 RM 们将 XID 对应的自己的本地事务进行提交还是回滚。
设 计 思 路
AT模式的核心是对业务无侵入,是一种改进后的两阶段提交,其设计思路如图
第一阶段
业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。核心在于对业务sql进行解析,转换成undolog,并同时
入库,这是怎么做的呢?先抛出一个概念DataSourceProxy代理数据源,通过名字大家大概也能基本猜到是什么个操作,后面做具体分析参考官方文档: Seata AT 模式
第二阶段
分布式事务操作成功,则TC通知RM异步删除undolog
分布式事务操作失败,TM向TC发送回滚请求,RM 收到协调器TC发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。
整体执行流程
设计亮点
相比与其它分布式事务框架,Seata架构的亮点主要有几个:
- 应用层基于SQL解析实现了自动补偿,从而最大程度的降低业务侵入性;
- 将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚;
- 通过全局锁实现了写隔离与读隔离。
存在的问题
性能损耗
一条Update的SQL,则需要全局事务xid获取(与TC通讯)、before image(解析SQL,查询一次数据库)、after image(查询一次数据库)、insert undo log(写一次数据库)、before commit(与TC通讯,判断锁冲突),这些操作都需要一次远程通讯RPC,而且是同步的。另外undo log写入时blob字段的插入性能也是不高的。每条写SQL都会增加这么多开销,粗略估计会增加5倍响应时间。
性价比
为了进行自动补偿,需要对所有交易生成前后镜像并持久化,可是在实际业务场景下,这个是成功率有多高,或者说分布式事务失败需要回滚的有多少比率?按照二八原则预估,为了20%的交易回滚,需要将80%的成功交易的响应时间增加5倍,这样的代价相比于让应用开发一个补偿交易是否是值得?
全局锁
热点数据
相比XA,Seata 虽然在一阶段成功后会释放数据库锁,但一阶段在commit前全局锁的判定也拉长了对数据锁的占有时间,这个开销比XA的prepare低多少需要根据实际业务场景进行测试。全局锁的引入实现了隔离性,但带来的问题就是阻塞,降低并发性,尤其是热点数据,这个问题会更加严重。
回滚锁释放时间
Seata在回滚时,需要先删除各节点的undo log,然后才能释放TC内存中的锁,所以如果第二阶段是回滚,释放锁的时间会更长。
死锁问题
Seata的引入全局锁会额外增加死锁的风险,但如果出现死锁,会不断进行重试,最后靠等待全局锁超时,这种方式并不优雅,也延长了对数据库锁的占有时间。
Seata快速开始
Seata Server(TC)环境搭建
先下载包(第一个相当于是seata的工具集,tar.gz是Linux版,zip是windows版)具体版本根据组件版本关系进行下载https://github.com/seata/seata/releases
首先将tar包上传到Linux上,解压
cd /opt/
tar -zxf seata-server-1.3.0.tar.gz
移动并重命名
mv seata /soft/seata130
将工具包里的script文件拖至/soft/seata130/ 文件下
修改配置文件
cd /opt/soft/seata130/conf/
vim file.conf
#修改一下内容
将mode = "file" 改为 mode = "db"
将连接数据库 url地址改为mysql的服务器地址,数据库名可改可不该
user="root"
password="abc123" #数据库密码
进入mysql数据库
mysql -uroot -pabc123
#创建数据库,名要和上面配置文件中的数据库名一样
create database seata_server
use seata_server;
source /opt/soft/seata130/script/server/db/mysql.sql
将Seata Server注册到Nacos,修改conf目录下的registry.conf配置
cd /opt/soft/seata130/conf
vim registry.conf
#修改内容
type="nacos"
serverAddr="192.168.187.150:8849" #改为nacos服务器的地址
namespace="public"
username="nacos"
password="nacos"
配置Nacos配置中心 registry.conf,跟上面一样,group名和上面的要保持一致
注意:如果配置了seata server使用nacos作为配置中心,则配置信息会从nacos读取,file.conf可以不用配置。 客户端配置registry.conf 使用nacos时也要注意group要和seata server中的group一致,默认group是"DEFAULT_GROUP"
cd opt/soft/seata130/script/config-center/config.txt,修改配置信息
配置事务分组, 要与客户端配置的事务分组一致
#my_test_tx_group需要与客户端保持一致 default需要跟客户端和registry.conf中registry中的cluster保持一致
(客户端properties配置:spring.cloud.alibaba.seata.tx‐service‐group=my_test_tx_group)
事务分组: 异地机房停电容错机制
my_test_tx_group 可以自定义 比如:(guangzhou、shanghai...) , 对应的client也要去设置
这里比如说,seata有两个组,一个在南京,一个在广州,my_test_tx_group可以定义去使用哪一个组,如果nanjing的seata都断电用不了了,则直接改为guangzhou组启动就可以了
我这里改为nanjing
启动nacos服务器
sh /opt/soft/nacos/bin/startup.sh
配置参数同步到Nacos
cd /opt/soft/seata130/script/config-center/nacos
#需要授权
chown 777 nacos-config.sh
# sh ${SEATAPATH}/script/config‐center/nacos/nacos‐config.sh ‐p 8850 -u nacos -w nacos
./nacos-conf.sh -p 8849 -u nacos -w nacos
参数说明:可跟
-h: host,默认值 localhost
-p: port,默认值 8848,这里改为nacos的端口号
-g: 配置分组,默认值为 'SEATA_GROUP'
-u: nacos用户名
-w: nacos密码
-t: 租户信息,对应 Nacos 的命名空间ID字段, 默认值为空 ''
成功后,进入nacos中心,就会看到很多的配置文件进去了
启动Seata Server,端口号可以自己随便给
# 命令启动: bin/seata-server.sh -h 127.0.0.1 -p 8091 -m db -n 1 -e test
cd /opt/soft/seata130/bin/
./seata.server.sh -p 9001 -n 1
./seata.server.sh -p 9002 -n 2
./seata.server.sh -p 9003 -n 3
启动成功后,进入nacos可看到,上面启动三个,这里seata-server的实例数应该是3,这样就相当于是seata集群
Seata Client快速开始
1)启动Seata server端,Seata server使用nacos作为配置中心和注册中心(上一步已完成)
2)配置微服务整合seata
添加依赖(用到几个服务,就在哪个服务中都添加依赖)
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐starter‐alibaba‐seata</artifactId>
</dependency>
各微服务对应数据库中添加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配置(涉及的微服模块都添加)
配置seata 服务事务分组,要与服务端nacos配置中心中service.vgroup_mapping的后缀对应
seata:
tx-service-group: nanjing
config:
nacos:
server-addr: 192.168.88.190:8850
username: nacos
password: nacos
namespace: public
type: nacos
registry:
nacos:
server-addr: 192.168.88.190:8850
username: nacos
password: nacos
namespace: public
在nacos配置中心上找到service.default.grouplist配置,改其配置参数为seata服务的端口与ip
微服务发起者(TM 方)需要添加@GlobalTransactional注解
分布式事务成功,模拟正常下单、扣库存,扣余额
分布式事务失败,模拟下单扣库存成功、扣余额失败,事务是否回滚