日升时奋斗,日落时自省
目录
1、简述
2、Seata优越性
3、Seata组成
4、Seata模式
4.1、XA 模式
4.2、AT 模式(默认模式)
4.3、TCC 模式
4.4、SAGA 模式
4.5、XA协议
5、Seata服务部署
5.1、文件数据源部署
5.1.1、下载并安装Seata
5.1.2、启动Seata服务
5.2.2、修改配置文件
5.2.3、Nacos中新增Seata配置
5.2.4、MySQL中新建Seata数据库
5.2.5、启动Seata服务
6、Seata模式实现
6.1、实现XA模式
6.1.1、添加Seata依赖
6.1.2、配置Seata信息
6.1.3、开启分布式事务
6.2、实现AT模式
6.2.1、新增undo_log表
6.2.2、设置AT模式
6.3、实现TCC模式
6.3.1、新建冻结表
6.3.2、新建TCC接口
6.3.3、新建TCC实现类
Try(T)中实现逻辑
Confirm(C)中实现逻辑
Cancel(C)中实现逻辑
6.4、Saga模式实现
7、注意事项
7.1、Seata的JDK版本要求
7.2、AT模式注意
1、简述
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式事务解决方案
注:因为注解@Transactional是不能满足分布式需求的
分布式事务定义:在分布式系统下,一个业务跨越多个服务或数据源,每个服务各自都是一个分支事务,要保证所有分支事务最终状态的一致性这样的事务就是分布式事务。
2、Seata优越性
本地事务:本地事务只能针对单个数据库的主要原因是,事务的原子性和一致性是基于数据库连接的。在一个数据库连接上执行的多个操作可以通过本地事务来保证原子性和一致性,因为它们共享同一个数据库连接和事务上下文。
分布式事务(Seata):分布式事务是通过将多个本地事务组合成一个全局事务,确保所有涉及的数据库或服务在一个事务中要么全部成功,要么全部回滚。分布式事务的实现需要一个统一的事务管理中心,用于协调和管理多个服务之间的事务操作。Seata 就是一个分布式事务解决方案,可以帮助处理分布式环境中的事务一致性问题(也就是数据一致性和可靠性)。
3、Seata组成
事务协调者 (Transaction Coordinator) : 简称 TC,它就是 Seata服务端,负责协调并管理分布式事务的执行。它是分布式事务的协调器,协调多个参与者的事务操作。事务协调者负责全局事务的创建、提交、回滚以及事务的状态管理。它通过全局事务 ID 来跟踪和协调分支事务的执行。
事务管理器(Transaction Manager) : 简称 TM,负责管理应用程序的本地事务 (分支事务)。事务管理器定义了全局事务的范围,负责将分支事务注册到全局事务中,并在全局事务的协调下,执行本地事务的提交或回滚。
资源管理器 (Resource Manager) : 简称 RM,管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
如下图所示:
4、Seata模式
Seata有以下四种模式:
4.1、XA 模式
它的性能相比其他事务模式要差一点,但能保证最严格的数据一致性。XA 模式需要设置为串行化隔离级别,相当于对数据添加了读写锁。另外连接资源需要在整个事务期间保持,这样可能会导致资源锁定问题,从而影响并发事务吞吐.
优点:实现简单、无业务侵入
缺点:性能差、必须实现 XA 协议、容易产生死锁
适用场景:隔离级别要求高,强一致性分阶段事务模型,牺牲了一定的可用性(保证了强一致性)
强一致性:就是同步执行,我的每一步都需要你等待,后续的所有流程执行结束,才会生效
4.2、AT 模式(默认模式)
解决了 XA 模式中锁占用时间过长的问题。它的主要特点是简单无侵入,强一致,学习成本低。缺点是需要遵守一定的开发规约,它并不是对所有的 SOL 类型都支持,有一定的使用限制。适应于通用的业务场景,但它并不适应于热点数据的高并发场景,像 SKU (Stock Keeping Unit,库存管理中的一个概念,用来唯一标识一个可售卖的商品)的库存的扣减。因为 AT 模式有应用层的全局锁,当需要对相同的数据修改操作时,需要使用全局锁控制事务的并发时序,实现上存在锁排队等待的机制。
优点: 简单、无业务侵入、事务强一致、学习成本低、性能高于 XA 模式D
缺点: 连接数据库支持(本地)事务、遵循一定的开发规范(Java 应用、通过JDBC 访问数据库)。
适用场景:通过场景,不适用于连接的数据库不支持 (本地)事务。
4.3、TCC 模式
业务层面的分布式事务解决方案,TCC,Try-Confirm-Cancel 模式,是一种通过三个步骤 (Try、Confirm、Cancel) 来实现分布式事务的模式。在 TCC 模式下,应用程序需要自行实现 Try、Confirm、Cance三个方法,分别表示尝试执行、确认提交和取消回滚。TCC 模式,不依赖于底层数据资源的事务支持:
一阶段 prepare 行为: 调用自定义的 prepare 逻辑
二阶段 commit 行为: 调用自定义的 commit 逻辑
二阶段 rollback 行为: 调用自定义的 rollback 逻辑
所谓 TCC 模式,是指支持把自定义的分支事务纳入到全局事务的管理中
优点: 灵活、性能高 (不依赖全局锁、不需要生成快照) 、不依赖数据库事务
缺点:业务侵入大、实现难度高 (自己实现事务操作的业务代码)、事务最终一致性 (不是强一致性)。
适用场景: 连接的数据库不支持 (本地)事务。
4.4、SAGA 模式
业务层面的分布式事务解决方案。个基于长事务的解决方案,Saga 模式解决的是在没有二阶段提交的情况下解决分布式事务。它的核心思想是将一个业务流程中的长事务拆分成多个本地短事务,业务流程中的每个参与者都真实的提交本地短事务,当其中有一个参与者的事务执行失败,则通过补偿机制补偿给前面已经执行成功的参与者
优点: 灵活、性能高、可异步化。
缺点: 无锁、不保证隔离性、业务侵入大。
适用场景: 长事务
注:相比而言,以基于数据库事务划分XA和AT归为一类,TCC和SAGA归为一类(AT比较常用,TCC和SAGA很用)
4.5、XA协议
XA 协议是一种标准的分布式事务协议,用于实现跨多个资源管理器(如数据库)的分布式事务的一致性。
XA 协议定义了在分布式环境下多个资源 (如数据库)之间进行事务协作的规范和接口。它使得每个资源管理器都能参与到全局事务中,并根据全局事务的指令进行相应的操作
XA 协议的核心是两阶段提交 (Two-Phase Commit,2PC) 机制:
第一阶段(准备阶段): 全局事务协调器向所有参与者发送准备请求,每个参与者执行本地事务并返回确认信息给协调器。如果所有参与者都返回成功,那么协调器进入第二阶段。如果有任何一个参与者返回失败,协调器将发送回滚请求。
第二阶段(提交/滚阶段) : 全局事务协调器根据第一阶段的反馈情况,决定提交或回滚全局事务。首先,协调器发送提交或回滚指令给所有参与者,然后参与者按照指令执行相应的操作。
如下图展示的是:两种情况,事务协调者给出的不同的结果
4.6、XA和AT的区别
基本有三个区别:
- XA模式一阶段(1PC)不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源
- XA模式依赖数据库机制实现回滚;AT模式利用数据快照由Seata实现数据回滚
- XA模式强一致,而AT模式最终一致
5、Seata服务部署
注:就是搭建TC服务,也叫做事务协调者
5.1、文件数据源部署
5.1.1、下载并安装Seata
直接去GitHub上找一下Seata下载个版本就行 ,我这里也提供给友友们一份网盘的1.7.0版
我们这里就采用1.7.0版本的
解压后里面的内容如上:
每个文件夹对应的作用:
- bin:存放启动Seata Server的脚本文件
- conf:Seata Server的配置目录
- lib:Seata Server的Jar包存放目录
- logs:存放日志文件
5.1.2、启动Seata服务
解压之后进入bin目录,双击 seata-server.bat就会启动了
双击相当于cmd在该路径下 输入 seata-server.bat -p 8091 -m file
Seata默认是以8091为端口号,file作为数据源
5.2.2、修改配置文件
修改conf/application.yml配置如下:
需要配置就是seata的是下的config,register,store数据库
注:可以从配置文件样例中找到相关配置,复制拷贝过来就行,需要改动就是访问地址 、用户名、密码
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
seata:
config:
# nacos配置
type: nacos
nacos:
server-addr: localhost:8848
namespace:
group: DEFAULT_GROUP
username: nacos
password: nacos
context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
data-id: seataServer.properties
registry:
# nacos注册
type: nacos
preferred-networks: 30.240.*
nacos:
application: seata-server
server-addr: localhost:8848
group: DEFAULT_GROUP
namespace:
cluster: default
username: nacos
password: nacos
context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
store:
# db 数据库
mode: db
session:
mode: db
lock:
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
user: root
password: 123456
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 1000
max-wait: 5000
# server:
# service-port: 8091 #If not configured, the default is '${server.port} + 1000'
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login
5.2.3、Nacos中新增Seata配置
将Seata存储修改为数据库
内容比较多, ctrl+F找一下相关内容如下:
需要改:
- url:自己数据库路径
- user:数据库用户
- password:数据库密码
注:这里seata库,下面会告诉友友们如何找,如何创建的
5.2.4、MySQL中新建Seata数据库
首先在本地数据库需要创建一个库叫做的seata(与上面配置数据库信息对应),然后执行mysql.sql脚本
我这里使用workbeach来给友友们演示(以下四个表)
其中表的含义:
- global_table:全局事务表
- branch_table:分支事务表
- lock_table:全局锁表
- distributed_lock:分支事务锁表(多服务集群下保证同时只有一个服务处理提交或回滚)
5.2.5、启动Seata服务
注:前面配置Nacos,所以在启动Seata之前需要先启动Nacos
进入到seata/bin目录,在路径位置输入cmd,其实双击seata-server.bat就行(开放端口7091)
控制台页面访问路径:localhost:7091
登录信息账户和密码都是seata,其实这个控制台基本用不到,用户和密码可以在config/application.yml中配置
6、Seata模式实现
这里准备了一个微服务项目,使用Spring Cloud多模块项目,以用户购买商品的业务逻辑
两个微服务提供支持:(项目在前面的网盘已经提供,项目名seata-demo)
- 库存服务:对给定的商品扣除库存数量
- 订单服务:根据采购需求创建订单
6.1、实现XA模式
注:基于XA协议的流程
注:1开头的表示第一阶段,2开头表示第二阶段
XA模式执行流程:(这里偷个懒,直接拿官网的图给友友们解释)
XA模式实现需要以下3步:
- 添加Seata依赖
- 配置Seata信息
- 开启分布式事务
6.1.1、添加Seata依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
6.1.2、配置Seata信息
seata:
application-id: seata-demo-business
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: ""
group: DEFAULT_GROUP
application: seata-server
username: nacos
password: nacos
tx-service-group: seata_tx_group
service:
vgroup-mapping:
seata_tx_group: default
data-source-proxy-mode: XA
配置解析:
- application-id:表示一个事务id,多个是服务相关一个事务,用同一个id
- registry:配置注册中心
- type:配置注册中心类型(与seata配置文件相同)
- nacos:相关配置
- application:由于我们配置seata的注册中心为nacos启动后seata会注册到nacos中服务名称叫做seata-server
- tx-service-group:事务组(被一个集群管理)这个是自己写的
- seata_tx_group:与上面是对应的,默认使用事务组
- data-source-proxy-mode:运行模式
6.1.3、开启分布式事务
需要使用@GlobalTransactional注解开启分布式事务,体现代码business服务中service层businessService(就是在调用两个库存的方法上添加全局事务注解)
@GlobalTransactional
public void purchase(String userId,
String commodityCode,
Integer orderCount) {
// 减库存
storageService.deduct(commodityCode, orderCount);
// 添加订单
orderService.create(userId, commodityCode, orderCount);
// 更新账户(代码省略...)
}
6.2、实现AT模式
AT模式执行流程如下:
还是基于XA执行流程来的,就是添加了一个表交undo_log表,用来存放执行SQL 的
注:提交事务就删除undo_log表的业务sql内容,回滚就让undo_log生成的逆sql恢复数据
AT模式多执行的两步:
- 在数据库中添加undo_log事务回滚
- 设置Seata运行模式为AT模式(或者删除运行模式,因为Seata默认就是AT模式)
6.2.1、新增undo_log表
这表网盘资料已经提供了(如果涉及到多个数据库,undo_log表每个涉及事务数据库都需要有该表)
在业务系统(TM事务管理器的项目)中,添加undo_log表,实现SQL
表的信息就是分支信息,内容状态修改id等(字段信息就是表达意思)
6.2.2、设置AT模式
只用修改 data-source-proxy-mode: AT 详细解释看XA模式配置解释(都是一样的)
seata:
application-id: seata-demo-business
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: ""
group: DEFAULT_GROUP
application: seata-server
username: nacos
password: nacos
tx-service-group: seata_tx_group
service:
vgroup-mapping:
seata_tx_group: default
data-source-proxy-mode: AT
6.3、实现TCC模式
TCC模式执行流程:
基本如下四步:
- 创建仓库(冻结表)
- 新建TCC接口,声明TCC调用方法
- 新建TCC实现类,实现方法
- 将调用方法更改为TCC实现类的方法
注:执行思路借用XA基本思想,只是预备、提交、回滚需要自己去写,数据存放在冻结表,如果如果数据正常就提交,并清空冻结表,如果需要回滚,从冻结表中取进行恢复,将冻结数量设置为0
6.3.1、新建冻结表
TCC模式服务仓库,在服务项目下创建(网盘中也提供了)
6.3.2、新建TCC接口
@LocalTCC开启TCC模式,注解TwoPhaseBusinessAction的三个参数:
value:try预备资源
commitMethod:如果是提交执行那个方法(写方法名)
rollbackMethod:如果是回滚执行那个方法(写方法名)
deduct中注解是为了对应TCC,注解参数
@LocalTCC
public interface TCCService {
/*
* try 逻辑和二阶段方法声明
* */
@TwoPhaseBusinessAction(name = "deduct",commitMethod = "confirm",rollbackMethod = "cancel")
void deduct(@BusinessActionContextParameter(paramName = "commodityCode")String commodityCode,
@BusinessActionContextParameter(paramName = "orderCount")Integer orderCount);
/*
* 二阶段 提交方法
* */
boolean confirm(BusinessActionContext context);
/*
* 二阶段回滚方法
* */
boolean cancel(BusinessActionContext context);
}
6.3.3、新建TCC实现类
TCC每个方法中实现逻辑业务
Try(T)中实现逻辑
扣减库存
仓库冻结表中添加数据
Confirm(C)中实现逻辑
根据XID(事务ID)删除冻结表的数据
Cancel(C)中实现逻辑
修改仓库,恢复冻结数量
修改冻结表的状态为2,冻结数量为0
注:具体实现项目中有库存服务中service层有Imp实现类,TCCServiceImpl类进行方法实现
6.4、Saga模式实现
Saga实现流程:
给友友们解释一下:
T表示事务执行,C表示事务回滚,后面的数字用来区分事务,箭头表示事务之间有关系
当T3事务失败时,就会进行回滚事务C3在回滚C2最后的回滚到C1
前面提到TCC和SAGA是比较类似,不需要数据库有事务功能,这里不在实现Saga
有想法的友友可以去官网看看:https://seata.io/zh-cn/docs/user/mode/saga
7、注意事项
7.1、Seata的JDK版本要求
稳定支持JDK8,11,其余可能会有问题
7.2、AT模式注意
- 支持数据库:mysql、Oracle、pgsql、mariadb
- 所有业务库都需要undo_log表(针对分库)
- 分布式事务中,消费者需要依赖、配置、注解,提供者可以不加全局事务注解、但是必须有依赖和配置