alibaba 微服务分布式事务组件-seata
1 事务简介
事务transtction 是访问并可能更新数据库中各种数据项的一个程序执行单元。在关系型数据库中,一个事务有一组sql 组成,事务应该具有4个属性:
-
原子性:一个事务是一个不可分割的工作单位,事务中包括诸多操作,要么都做,要么都不做;
-
一直性:事务必须是是数据库从一个一直状态变到另一个一直性状态,事务中间状态不能被观察到;
-
隔离性:一个事务的执行官不能被其他事务干扰,即一个事务内部的操作及使用的数据库对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰;
-
持久性:持久性也称为永久性,值一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其他操作或故障不应该对齐有任何影响;
任何事务机制在实现时,都应该考虑事务的ACID特性;包括,本地事务,分布式事务,及时不能都很好的满足,也要考虑支持到什么程度;
2 本地事务
@Tranactional
大多数场景下,我们的应用都只需要操作单一的数据库,这种情况下事务称为本地事务(local Tranaction)。本地事务的ACID特性是数据库直接提供支持。本地事务应用架构图如下;
在JDBC 编码中,我们通多java.sql.Connection
对象来开启、关闭或者提交事务,代码如下:
Connection conn =
conn.setAutoCommit(false);// 关闭事务自动提交
try{
conn.commit(); //提交事务
}catch(Exception e){
conn.rollback();//事务回滚
}finally{
conn.close();//关闭连接
}
3 分布式事务:
业务模型:
4 seata
介绍:
seata 是一款开源的分布式解决方案;致力于提供高性能和简单易用的分布式事务服务; seata 将为用户提供AT\TCC\SAGA和XA事务模式;为用户打造一站式分布式解决方案。AT模式是阿里首推的模式,阿里云上有上永伴的GTS (global transaction service 全局事务服务)
官网地址: http://seata.io
seata版 1.4.0
4.1 seata的三大角色
-
TC 事务协调者:维护全局和分支事务的状态,驱动全局事务的提交或者回滚;
-
TM 事务管理器: 定义全局事务的方位,开始全局事务、提交或回滚全局事务;
-
RM 资源管理器: 管理分支事务处理的资源,与TC 交谈,以注册分支事务和报告分支事务的状态,并驱动分支事务的提供和回滚;
其中,TC为单独部署的server服务端,TM和RM 为嵌入到应用中的client客户端;
TM 请求TC 开启一个全局事务,tc会生成一个XID 作为该全局事务的编号。xid,会再微服务的调用链路中传播,保证多个微服务的子事务关联在一起
RM请求TC将本地事务注册为全局事务的分支事务,通过全局事务的xid进行关联;
TM请求TC 告诉XID对应的全局事务是进行提交还是回滚;
TC 驱动RM们将xid对应的自己的本地事务进行提交还是回滚;
4.2 常见分布式事务解决方案
- seata 阿里分布式框架 at
- 消息队列 tcc
- saga saga
- xa xa
他们都有两阶段(2PC).两阶段 是指完成分布式事务,划分成两个步骤。
实际上,这个是四种常见的分布式解决方案,分别对应着分布式事务的四种模式:AT TCC SAGA XA(全局事务、基于可靠消息、最大努力通知、TCC)
4.3 分布式事务理论基础
解决分布式事务,也有相应的规范和协议。分布式事务相关的协议有2PC、3PC
由于三段提交协议3PC 非常难实现,目前市面主流的分布式事务解决方案都是2PC协议。
4.4 两阶段提交协议
2pc two-phase comit
顾名思义 分为两个阶段 prepare 和commit
seata 参与者为数据库 ,tcc中间件 一般参与者指的是应用或者服务
基本流程图
示例:
4.5 2PC的问题
-
同步阻塞参与者在等待协调者的指令时,其实是在等待其他参与者的响应,在此过程中,参与者是无法进行其他操作的。也就是阻塞了其运行。倘若参与者与协调者之间的网络异常导致参与者一直收不到协调者信息,那么就会导致参与者一直阻塞下去。
-
单点在2PC中,一切请求都来自协调者,所以协调者的地址直观重要,如果协调者单机,那么就会是参与者一直阻塞并一直占用事务资源。(避免单点故障,新的节点不能处理上一个事务)
-
数据不一致,commit事务过程中,commit请求/rollback请求,可能因为协调者宕机或协调者与参与者网络异常丢失,那么就会导致部分参与者没有收到commit/rollback请求,而其他参与者则正常收到执行了commit/rollback操作,没有收到请求的参与者则继续阻塞,这时名参与者之间的数据就不在一致了。
当参与者commit/rollback后会向协调者发送ACK ,然而协调者不论是否收到所有参与者的ack,该事务也不会再有其他的补救措施了,协调者能做的也就是等超时后想事务发起者返回一个 ‘我不确定事务是否成功’
-
环境可靠性依赖,协调者 prepare请求后,等待响应,然而如果有参与者宕机或协调者之间网络中断,都会导致协调者无法收到所有参与者的响应,那么在2PC中,协调者都会等待一定时间,然后超时后,会触发事务中断,在这个过程中,协调者和所有其他参与者都是出于阻塞的。这种机制对网络问题常键的实现环境来说太苛刻。
4.6 AT模式(auto transaction)
4.61 AT 模式是一种无侵入的分布式事务解决方案;
阿里 seata框架实现该模式;
在AT模式下,用户只需关注自己的业务sql,用户的业务sql 作为第一个阶段,seata框架会自动声称该无的第二阶段提交和回滚操作;
4.6.2 AT 模式如何做到对业务的无入侵
- 第一阶段,seata会拦截"业务sql" ,首先解析sql语义,找到“业务sql”要更新的业务数据,在业务数据被更新前,将其保存为“before image”,然后执行“业务sql”更新业务数据,在业务数据被更新之后,在将其保存成“after image”,最后生成杭锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作原子性。
-
第二阶段提交
第二阶段如果是提交的话,因为“业务sql”在一极端已经提交至数据库,所以seata框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可;
-
二阶段回滚
二阶段如果是回滚的话,seata 就需要回滚一阶段已经执行的“业务sql” ,还原业务数据。回滚方式便是用before image 还原业务数据;但在还原之前首先要校验脏读,对比“数据库当前业务数据”和“after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就会说明有脏写,出现脏写就要转人工处理。
4.7 TCC 模式
1、侵入性比较强,并且得自己实相关事务控制逻辑;
2、在整个过程中没有锁的概念,性能更好;
3、tcc 开源框架:beyeTcc 、tcc-transaction 、himly
tcc模式需要用户根据自己的业务场景实现,try confirm 和cancel 三个操作。事务发起方在一阶段执行try方式,在二阶段执行提交confirm方法,二阶段回滚执行cancel 方法;
示例:
4.8 MQ 模式
称为可靠消息最终一致性解决方案(rocketMq 有事务消息,所以解决起来比较方便)
4.9 seata at模式原理
第一阶段:
第二阶段:
分布式事务操作成功,TC通知rm异步删除undolog
分布式事务操作失败,TM 向TC 发送回滚请求,RM收到协调器TC发来的回滚请求,通过XID和branch ID 找到相应的回滚日志记录,通过回滚记录生成的方向更新sql并执行,以完成分支的回滚。
5 开始使用seata
@GlobalTransational 开启全局分布式事务
5.1 seata server 环境搭建
server 端存储模式支持三种:
- file 单机模式,全局事务回话信息内存中读取并持久化到本地文件root.data,性能较高(默认)
- db,高可用模式,全局事务会化通过db共享,响应性能较差些
- redis,seata-server1.3 及以上版本支持,性能较高,存在事务信息丢失风险,提前配置合适当前场景的redis持久化配置
资源目录介绍:
-
client
存放client端sql脚本(包含undo_log表),参数配置
-
config-center
各个配置中心参数导入脚本,config.text(包含server和client,原名nacos-config.txt)为通过用参数文件
-
server
server端数据库脚本(包含lock_table,brach_table和global_table)及各个容器配置
5.2 搭建环境脑图
5.3 seata 高可用集群
5.4 在版本对照表
在使用springcloud alibaba 他们的组件的时候,记得使用版本对照表,要不然会出现一些莫名其妙的情况。
5.5 springcloud 代码应用
5.5.1 导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
</dependency>
5.5.2 导入数据库表到微服务数据库中
官方网站文件的位置:\script\client\at\db
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
5.5.3 配置事务分组
这里对应service.vgroupMapping.my_test_tx_group=default
的my_test_tx_group
alibaba:
seata:
tx-service-group: txgroup
5.5.4 配置seata client 访问 seata tc
seata:
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848 #seata server 所在的nacos 服务地址
application: seata_server #seata server 服务名
username: nacos #seata server 所在的nacos 账号
password: nacos #seata server 所在的nacos 密码
group: SEATA_GROUP #seata server 所在的nacos 分组
config: #配置seata的配置中心,可以读取关于seata client的一些配置
type: nacos
nacos:
server-addr: 127.0.0.1:8848 #seata server 所在的nacos 服务地址
application: seata_server #seata server 服务名
username: nacos #seata server 所在的nacos 账号
password: nacos #seata server 所在的nacos 密码
group: SEATA_GROUP #seata server 所在的nacos 分组
5.5.5 使用@GobalTranactional
这样就完成了 整个分布式事务,seata at 模式的事务