seata分布式事务解决方案
一 什么是seata
前言:seata我之前在生产中用过几次,但是不可避免,其确实存在写性能上的问题,后续只能在seata的基础上完善成增加异步处理+最终一致性的解决方案,所以没有什么架构是完美的。
先通过如下的图,大致了解一下seata的架构:
我做一个简短的总结,然后再仔细的讲解:
seata主要构成可以简单记忆为:,三组件+一个Id:
全局id: transactionId 全局唯一事务ID
三组件:
TC - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚,大白话:负责通知命令的中间件Seata-Server(传令官)
TM - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务,大白话:决定什么时候全局提交/回滚(司令官)
RM - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚,大白话:做具体事儿的工具人(大头兵)
接下来我们详细了解一下seata:
看一下如下的场景,如果在单一系统或者项目中,肯定直接使用事务注解就可以实现,但是微服务场景下,每个项目都是自己独立的库,就不太好解决了。
二 传统的分布式事务
TC作为事务协调者,其最大的作用就是与每一个子事务进行通讯,通讯是分为几步的:
前提:子模块的TM来TC注册,告诉我当前事务是需要参与分布式事务的,获取到XID
- 任务来临,TC通知对应的子模块,开始处理你的事务,并告知我结果
- 子模块处理成功后,并不会自动提交
- TC收到所有此XID的所有成功的响应
- TC通知所有模块提交
注意:此过程我们提交了两次,一次是向TC成功的信息,一次是自己数据的正式提交,所以称为2PC,二阶段提交。
三 seata
前言: 如何搭建配置seata请看我的springCloud ALiababa专题。
我们先看看如何开启一个分布式事务:
GlobalTransactional是seata提供开起事务的注解。
后续步骤:
此处跟传统的处理方式不同:
- 本地成功后,会在本地立即提交
后续:
后续:
四 seata如何实现的回滚的?
前言:此处是at模式
原理:seata的每个rm其实都建立了一张UNDO_LOG的表,此表记录了事务执行的回滚sql记录。
如下图:
五 seata怎么处理并发,脏数据的?
脏数据概要总结:
分阶段:
before image
执行sql
after image
生成行锁
提交 生成undo日志
如果提交成功
就会删除bi ai 解锁
如果提交失败
校验脏写 校验ai 和 当前数据库是否一致
如果一致 证明数据没有被别人修改 直接还原bi 同时异步的执行和删除
如果不一致 则需要人工处理/ 如果你加了分布式锁 则不需要人工处理
基于以上概要流程,我们来看下图:
讲解并发:
- tc自带分布式锁
- tx1进来的时候,如果当前事务没有处理完成,会给当前数据增加全局锁
- tx2进来,如果当前数据具备全局锁,就会一直处理等待状态
- tx1释放锁
- tx2获取锁
总结: