SpringCloud高级(四) ——SpringCloud Alibaba Seata原理简介
Seata之原理简介
TC,TM,RM
理解:TC
通过统一的Xid
协调RM
。
分布式事务的执行流程:
-
TM
开启分布式事务(TM
向TC
注册全局事务记录)。加注解GlobalTransactional
即开启 - 换业务场景,编排数据库,服务等事务内资源(
RM
向TC
汇报资源准备状态) -
TM
结束分布式事务,事务一阶段结束(TM
通知TC
提交/回滚分布式事务) -
TC
汇总事务信息,决定分布式事务是提交还是回滚 -
TC
通知所有RM
提交/回滚资源,事务二阶段结束。
什么是一阶段,二阶段?
AT模式
Spring AOP思想+回退反写机制
一阶段加载
在一阶段,seata
会拦截"业务sql
":
- 解析
sql
语义,找到业务sql要更新的业务数据,在业务数据被更新前,将其保存成"before image
" - 执行业务
sql
,更新业务数据 - 在业务
sql
数据更新之后,将其保存成"after image
",最后生成行锁
以上操作全部在一个数据库事务(这个事务是本地事务会被RM注册为分支事务)内完成,这样保证了一阶段的原子性。
原理图:AOP
思想:前置通知,后置通知
二阶段提交
根据第一阶段的情况决定是进行全局提交还是全局回滚操作。对服务端来说,等到一阶段完成未抛异常,全局事务的发起方TM
会向服务端申请提交这个全局事务。
如果一切顺利,各个RM
执行分支事务都正常,又因为各个RM
的业务sql
已经在一阶段提交至数据库了,所以seata
框架只需要将一阶段保存的快照数据和行锁删掉,完成数据清理即可。
二阶段回滚
如果一阶段执行某个业务sql
出现了异常,二阶段就要进行全局回滚,回滚一阶段已经执行的业务sql
,还原业务数据。
回滚方式便是通过"before image
“还原业务数据,但在还原前要首先校验脏写,对比数据库当前业务数据和”after image
",如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。
debug
例如:某个业务服务,跨库调用了库存和账户的微服务
账户微服务接口打个断点:
1.此时,查看seata
库branch_table
分支事务表:
xid:ip+端口+全局事务id组成,一个全局事务下,有多个分支事务,其他信息如图。
2.查看订单库的,undo_log
事务回滚表
可以看到这个订单表的分支事务是全局事务2016993159
的一个分支事务。
把rollback_info
内容复制一下:发现了前置镜像和后置镜像,这不就是为了二阶段回滚的时候,拿来恢复数据嘛,就是防止一阶段出现了异常,但是业务sql
已经执行了,因为已经备份了数据,可以进行反向补偿!
查看库存的ubdo_log以及账户的undo_log,也都是类似的,都有自己的分支事务id,还有备份的前置镜像,后置镜像。
3.查看全局事务表:Xid
,全局事务id
都和分支事务表关联着;
事务名就是注解GlobalTransactional
的name
属性指定的那个;
应用id全局事务所处的微服务的名字;transaction_service_group
就是配置文件里配的tx-service-group
的值
4.查看锁表
这里账户表锁的是主键为1的记录;
这里订单表锁的是主键为30的记录;
这里库存表锁的是主键为1的记录;
5.从断点处,直接执行完毕
从新刷新表branch_table,global_table,lock_table发现数据全被删了
undo_log也是
二阶段会把中间数据清了。
深入源码
https://blog.****.net/hosaos/article/details/89403552