分布式事务产生背景
数据库拆分
- 单库单表支撑不了业务时需要对数据库进行水平拆分。分库分表后,原来在一个数据库上就能完成的写操作,可能会跨多个数据库,就产生了跨数据库事务问题
业务服务化拆分
- 业务拆分后,一个完整的业务逻辑可能会涉及多个服务,多个服务之间存在跨服务事务问题
分布式事务理论基础
两阶段提交协议(对应阿里的AT模式)
事务管理器分为两个阶段来协调资源管理器,第一阶段准备资源,也就是预留事务所需资源,如果资源管理器资源预留成功,则进行第二阶段资源提交,否则协调资源管理器回滚资源
例如:扣款流程,第一步先冻结资金,冻结成功后进行第二步扣款,扣除成功则把事务提交。若第二步扣款失败则将第一步回滚,恢复冻结资金
TCC (Try-Confirm-Cancel)
实际上是对服务化的两个阶段提交协议,业务开发者需要实现这三个服务接口,第一阶段服务自由业务代码编排来调用Try接口进行资源预留,所有参与者的Try接口都成功了,事务管理器会提交事务,并调用每个参与者的Confirm接口真正提交业务操作,否则调用每个参与者的Cancel接口回滚事务
Saga
- saga是一种补偿协议,在Saga模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作
- 分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态
- Saga正向服务与补偿服务也需要业务开发者实现
其实TCC、Saga都是两阶段提交的补充
Seata概述
- Simple Extensible Autonomous Transaction Architecture 简单可扩展自治事务框架。2019年1月开源
2019年1月开源
- 三大模块,TM、RM、TC。其中TM和RM是作为Seata的客户端与业务系统集成在一起,TC作为Seata的服务端独立部署
- 有四种分布式解决方案,AT模式、TCC模式、Saga模式和XA模式
Seata模块
三大模块
- TC(Transaction Coordinator):事务协调器
维护全局和分支事务的状态,用于全局性事务的提交和回滚 - TM(Transaction Manager): 事务管理器
定义全局事务域:开启全局事务、提交或者回滚全局事务。向事务指定标识,监视它们的进场,并负责处理事务的完成和失败。事务分支标识(称为XID)由TM指定,以标识一个RM内的全局事务和特定分支 - RM(Resource Manager):资源管理器
管理分支事务所使用的资源,向TC注册分支事务并报告分支事务状态,接受TC的命令来提交或者回滚分支事务
Seata管理分布式事务典型的生命周期
- TM向TC请求开始全局事务,TC生成一个代表全局性事务的XID
- XID通过微服务的调用链传播
- RM向TC注册本地事务,作为XID对应的全局事务的分支
- TM要求TC提交或者回滚XID相应的全局事务
- TC驱动XID相应的全局事务下的分支事务完成分支的提交或者回滚
AT模式
AT模式是一种无入侵的分布式事务解决方案。在AT模式下,用户只需关注自己的业务SQL,用户的业务SQL作为一阶段,seata框架会自动生成事务的二阶段提交和回滚操作
AT模式-第一阶段
seata会拦截“业务SQL”,首先解析SQL语义,找到业务sql要更新的业务数据,在业务数据被更新前,将其保存成before image,然后执行业务sql更新业务数据,在业务数据更新之后,再将其保存成after image,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性
AT模式-第二阶段
二阶段如果是提交的话,因为业务sql在一阶段已经提交至数据库,所以seata框架只需将一阶段保存的快照数据和行锁删除,完成数据清理即可
TCC模式基本原理
分为Try-Confirm-Cancel 3个操作。其和两阶段提交有点类似,Try为第一阶段,Confirm-Cancel为第二阶段,是一种应用层面侵入业务的两阶段提交
操作方法 | 含义 |
Try | 预留业务资源/数据校验 |
Confirm | 确认执行业务操作,实际提交数据,不做任何业务检查,try成功,confirm必定成功,需要保证幂等 |
Cancel | 取消执行业务操作,实际回滚数据需保证幂等 |
其核心在于将业务分为两个操作步骤完成。不依赖RM对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。相对于AT模式,TCC模式对业务代码有一定的入侵性,但是TCC模式无AT模式的全局行锁,TCC性能会比AT模式高很多
TCC模式原理图
TCC幂等操作
使用TCC时需要注意Try-Confirm-Cancel 3个操作的幂等控制,网络原因,或者重试操作都有可能导致这几个操作的重复执行
TCC空回滚
事务协调器在调用TCC一阶段Try操作时,可能会出现因为丢包而导致网络超时,此时事务协调器会触发二阶段回滚,TCC在未收到Try请求的情况下收到Cancel请求,这种场景被称为空回滚。
解决思路:
回滚请求处理时,如果对应的具体业务数据为空,则返回成功,让事务服务管理器认为已回滚,否则会不断重试,而Cancel又没有对应的业务数据可以进行回滚
TCC防悬挂
事务协调器在调用TCC服务的一阶段Try操作时,可能会出现因网络拥堵而导致的超时,此时事务协调器会触发二阶段回滚,调用TCC服务的Cancel操作;在此之后,拥堵在网络上的一阶段Try数据包被TCC服务收到,出现二阶段Cancel请求比一阶段Try请求先执行的情况;
解决思路:
在二阶段执行时插入一条事务控制记录,状态为已回滚,这样当一阶段执行时,先读取记录,如果记录存在,就认为二阶段回滚操作已经执行,不再执行Try方法
Saga模式
长事务解决方案。
Saga模式使用场景
- 适用于业务流程长且徐亚保证事务最终一致性的业务系统
- 无法进行改造和提供TCC要求的接口,可以使用Saga模式
Saga模式优势
- 无锁,高性能
- 异步执行,高吞吐
- 补充服务容易理解,容易实现
TM事务管理器
开启、提交、回滚分布式事务
RM 资源管理器
注册、汇报、执行资源
TC 事务管理器服务功能
存储事务管理日志,补偿异常事务
tcc事物
在同一个service里面
@GlobalTransactional
@Transactional
service(){
// tcc事务 第一阶段返回true
serviceA.tcc();
// 本地事务失败
serviceB.update();
// tcc事务会走back回滚
}
如果里面的本地事务失败,那么tcc事务会走back回滚