分布式事务--2PC(两阶段提交)
什么是2PC?
即两阶段提交协议,将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase),2指的是两个阶段,P指的是准备阶段,C指的是提交阶段
1.准备阶段:事务管理器给每个参与者发布Prepare消息,每个服务参与者在本地执行事务,并写在Undo/Redo日志,此时事务没有提交。(Undo日志记录修改前数据用于回滚,Redo记录修改后数据用于提交事务后写入数据文件)
2.提交阶段:如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者进行回滚,否则发送提交消息。注意:必须在最后阶段释放锁资源
XA方案
2PC的传统方案实在数据库层面实现的,比如MySQL、Oracle都支持2PC协议。
执行流程:
1.应用程序持有用户库和积分库两个数据源
2.应用程序通过TM通知用户库RM新增用户,同时通知积分库RM为该用户新增积分,RM此时并未提交事务,此时用户和积分资源锁定
3.TM收到执行回复,只要一方失败则分别向其他RM发起事务回滚,回滚完毕释放资源
4.TM收到执行回复,全部成功,此时向所有RM发起提交事务,提交完毕,资源锁释放
DTP模型定义如下角色:
AP:即应用程序,可以理解为使用DTP分布式事务的程序
RM:即资源管理器,可以理解为事务的参与者,一般指的时数据库实例,通过资源管理器对该数据库进行控制分支事务
TM:事务管理器,负责协调和管理事务,控制全局事务,协调各个RM。
DTP模式定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接口协议。
XA方案的问题:
1.需要本地数据库支持XA协议
2.资源锁定需要等到两个阶段结束才能释放,性能比较差。
Seata方案
Seata把分布式事务理解成一个包含了若干分支事务的全局事务。全局事务协调其下分支事务达成一致,要么一起成功提交,要么一起失败回滚。
Seata定义了3个组件来协议分布式事务的处理过程:
Transaction Coordinator(TC):事务协调器,维护全局事务的运行状态,收到TM指令,发起全局事务的提交和回滚。(独立的中间件,需要独立部署运行)
Transaction Manager(TM):事务管理器,TM需要嵌入应用程序中,负责开启一个全局事务,并最终向TC发起全局提交或全局回滚指令
Resource Manager(RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器TC的指令,驱动分支事务提交和回滚。
具体的执行流程如下:
Seata实现2PC与传统2PC的差别
架构层面:传统2PC方案的RM在数据库层,RM本质上就是数据库本身,通过XA协议实现。Seata的RM是以jar包的形式作为中间件层部署在应用程序这一侧
两阶段提交方面:传统2PC无论commit还是rollback,事务性资源的锁都保持到二阶段结束才释放。Seata实在一阶段本地事务提交,可以省去二阶段持锁的时间,提高整体效率。
重点:
1.第一阶段undo_log中存放了数据修改前的和修改后的值,为事务回滚做好准备,因此第一阶段已经将分支事务提交并释放锁资源
2.TM开始全局事务开始,将XID全局事务id放到事务上下文中,通过feign调用也将XID传入下游分支事务,每个分支事务将自己的Branch ID分支事务ID与XID关联
3.第二阶段全局事务提交,TC会通知各个分支参与者提交分支事务,在一阶段中已经提交,这里只需要删除undo_log即可。
4.第二阶段全局事务回滚,TC会通知各个分支参与者回滚事务分支,通过XID和Branch ID找到对应的回滚日志,根据回滚日志生成反向SQL并执行,回滚到之前的状态,回滚失败则会重试回滚操作。
5.RM使用DataSourceProxy连接数据库,目的是使用ConnectionProxy,保证第一阶段将undo_log和业务数据放在一个本地事务提交。保证只要有业务操作就一定有undo_log。