一、Seata概念介绍
1、Seata 是什么?
Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案。
seata下载:http://seata.io/en-us/blog/download.html
选择自己的版本下载
seat中文文档:http://seata.io/zh-cn/docs/overview/what-is-seata.html
这里我们只介绍默认的AT模式与TCC模式。
2、Seata默认的AT模式介绍
前提
基于支持本地ACID事务的关系型数据库。
Java应用,通过JDBC访问数据库。
整体机制
两阶段提交协议的演变:
一阶段:
业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:
提交异步化,非常快速地完成。
回滚通过一阶段的回滚日志进行反向补偿。
写隔离
一阶段本地事务提交前,需要确保先拿到全局锁。拿不到全局锁,不能提交本地事务。拿全局锁的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。以一个示例来说明:
两个全局事务tx1和tx2,分别对a表的m字段进行更新操作,m的初始值1000。
tx1先开始,开启本地事务,拿到本地锁,更新操作m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的全局锁,本地提交释放本地锁。tx2后开始,开启本地事务,拿到本地锁,更新操作m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的全局锁,tx1全局提交前,该记录的全局锁被tx1持有,tx2需要重试等待全局锁。
tx1二阶段全局提交,释放全局锁 。tx2拿到全局锁 提交本地事务。
如果tx1的二阶段全局回滚,则tx1需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。
此时,如果tx2仍在等待该数据的全局锁,同时持有本地锁,则tx1的分支回滚会失败。分支的回滚会一直重试,直到tx2的全局锁等锁超时,放弃全局锁并回滚本地事务释放本地锁,tx1的分支回滚最终成功。
因为整个过程全局锁在tx1结束前一直是被tx1持有的,所以不会发生脏写的问题。
读隔离
在数据库本地事务隔离级别读已提交(Read Committed)或以上的基础上,Seata(AT 模式)的默认全局隔离级别是读未提交(Read Uncommitted)。
如果应用在特定场景下,必需要求全局的读已提交 ,目前Seata的方式是通过SELECT FOR UPDATE语句的代理。
SELECT FOR UPDATE语句的执行会申请全局锁 ,如果 全局锁被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE语句的本地执行)并重试。这个过程中,查询是被block住的,直到 全局锁拿到,即读取的相关数据是 已提交 的,才返回。
出于总体性能上的考虑,Seata目前的方案并没有对所有SELECT语句都进行代理,仅针对FOR UPDATE 的SELECT语句。
3、TCC模式
回顾总览中的描述:一个分布式的全局事务,整体是两阶段提交的模型。全局事务是由若干分支事务组成的,分支事务要满足两阶段提交的模型要求,即需要每个分支事务都具备自己的:
- 一阶段prepare行为
- 二阶段commit或rollback行为
根据两阶段行为模式的不同,我们将分支事务划分为Automatic (Branch) Transaction Mode和Manual (Branch) Transaction Mode。
AT模式基于支持本地ACID事务的关系型数据库:
- 一阶段prepare行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
- 二阶段commit行为:马上成功结束,自动异步批量清理回滚日志。
- 二阶段rollback行为:通过回滚日志,自动生成补偿操作,完成数据回滚。
相应的TCC模式,不依赖于底层数据资源的事务支持:
- 一阶段prepare行为:调用自定义的prepare逻辑。
- 二阶段commit行为:调用自定义的commit逻辑。
- 二阶段rollback行为:调用自定义的rollback逻辑。
所谓TCC模式,是指支持把自定义的分支事务纳入到全局事务的管理中。
二、seata服务端与nacos整合开发
1、配置seata的服务器端的数据库
https://github.com/seata/seata/tree/1.2.0/script
server端脚本如下,同时也支持docker、kubernatesa安装
1)全局事务会话信息由3块内容构成,全局事务-->分支事务-->全局锁,对应表global_table、branch_table、lock_table 1;建立一个数据库名字随意用来做seata服务端的库,存储全局事务的会话信息
2)拿到服务端数据库的脚本文件执行并且建立表第1步三张表
https://github.com/seata/seata/tree/1.2.0/script/server/db 上面地址可以拿到数据库脚本,选择mysql然后自己执行。
2、修改服务端启动包的文件
1)启动包: seata-->conf-->file.conf,修改store.mode="db"。
2)修改file.conf自己的db连接信息
## transaction log store, only used in seata-server
store {
## store mode: file、db
mode = "db"
## database store property
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
datasource = "druid"
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/seata?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true"
user = "root"
password = "root"
minConn = 5
maxConn = 1000
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
}
这些信息是存在file.conf当中的也就是seata启动的时候会去读取这个配置文件;如果我们使用nacos可以把这些信息放到nacos的注册中心,从而实现动态更新。
如果你需要把这些信息放到nacos配置中心就需要修改seata-->conf-->registy.conf文件当中的注册中心和配置中心的信息,修改成为nacos;(为什么需要修改config和register呢?因为如果你的seata服务器想要去配置中心读取配置,那么一定到得把自己注册到nacos;所以registy.conf当中需要配置注册中心的地址也需要配置配置中心的地址) 这样我们如果后面启动seata就可以看到他是作为了一个nacos的客户端注册到了nacos的注册中心的;记住这点seata已经可以作为客户端注册到nacos了。
3、Seata部署指南
Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。
资源目录介绍:https://github.com/seata/seata/tree/1.2.0/script
Client:存放client端sql脚本,参数配置。
config-center:各个配置中心参数导入脚本,config.txt(包含server和client,原名nacos-config.txt)为通用参数文件。
Server:server端数据库脚本及各个容器配置。
注意事项:
seata-spring-boot-starter
内置GlobalTransactionScanner自动初始化功能,若外部实现初始化,请参考SeataAutoConfiguration保证依赖加载顺序
默认开启数据源自动代理,可配置seata.enable-auto-data-source-proxy: false关闭
spring-cloud-alibaba-seata
查看版本说明 2.1.0内嵌seata-all 0.7.1,2.1.1内嵌seata-all 0.9.0,2.2.0内嵌seata-spring-boot-starter 1.0.0
2.1.0和2.1.1兼容starter解决方案:
2.1.0和2.1.1兼容starter解决方案: @SpringBootApplication注解内exclude掉spring-cloud-alibaba-seata内的com.alibaba.cloud.seata.GlobalTransactionAutoConfiguration
3、把配置信息上传到nacos配置中心
第一步:启动nacos
第二步:访问https://github.com/seata/seata/tree/1.2.0/script/config-center到这个地址上面获取config.txt,然后把config.txt复制到idea当中去编辑,推荐使用idea编辑,因为可能有编码原因,保留自己想要的信息。
这里给出的是精简后的,你们需要自己对应修改自己的信息;主要是数据库配置信息。注意这些信息是服务器端和客户端都要使用的;由于上面我们已经把seata注册到了nacos;所以他的file.conf当中的信息可以直接从nacos读取;也就是下面我们配置的信息;换句话说如果你配置了seata作为nacos的一个客户端去读取配置那么file.conf可以不用配置了;这两步是重复的;这也是网上很多资料没有说明的;换成大白话的意思就是你如果配置了registy.conf那么file.conf当中的信息基本无效——都是从配置中心读取;甚至可以删了file.conf;你们可以自己测试;如果你不配置registy.conf,那么seata就会从file.conf当中读取配置;所以file.conf和registy.conf其实只需要配置一个。
3.1、精简后的配置如下:
#事务分组——my_test_tx_group 这值会在我们客户端对应,需要注意
service.vgroupMapping.my_test_tx_group=default
service.default.grouplist=127.0.0.1:8091
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://ip::3306/seata?useUnicode=true
store.db.user=root
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
那么这些精简后的配置如何传到nacos呢?
https://github.com/seata/seata/tree/1.2.0/script/config-center 从上面这个地址下载nacos文件下面的nacos-config.sh文件然后执行sh 你下载后的路径/nacos-config.sh;当然如果你的nacos地址不是默认的,需要修改naocs-config.sh当中指定你的路径;也可以在sh命令后面指定;
https://github.com/seata/seata/tree/1.2.0/script/config-center这个地址里面有个README.md文件有说明。
3.2、Nacos执行shell命令配置:
bash
sh ${SEATAPATH}/script/config-center/nacos/nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t ‘namespace’
参数说明:
-h: host, the default value is localhost
-p: port, the default value is 8848
-g: Configure grouping, the default value is 'SEATA_GROUP'
-t: Tenant information, corresponding to the namespace ID field of Nacos, the default value is ''
注意:
这里我们在Nacos配置里面创建一个namespace叫seata,ID为seata_id
3.3、cd到Nacos文件夹所在目录执行命令:
sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t seata_id