分布式事务场景
- 单体应用中访问多个数据库实例(跨数据库实例)
- 多个微服务应用(跨JVM)访问同一个数据库实例
分布式事务解决方案
由AP(微服务应用)、TM(事务管理器)、RM(资源管理器)三个部分组成,整个事务分为2阶段:
a、准备阶段:AP各自将本地事务进行预提交并将结果反馈给TM(如果TM出现故障则会导致全局事务不一致)
b、提交阶段:TM根据AP反馈结果对各个RM进行统一提交或回滚(若提交阶段出现失败则会导致全局事务不一致)
基于数据库层面的分布式事务,各个RM持有的数据库资源锁需要等到提交阶段结束后才能被释放(保证了事务的强一致性,但牺牲了数据库的链接数量)
- Seata(2PC)
将分布式事务理解成多个本地分支事务的全局事务(负责协调各本地分支事务,要么全部成功,要么全部失败)
分别由以下3个组件组成:
TC 事务协调器:维护全局和分支事务的状态,驱动全局事务提交或回滚
TM 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务
RM 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
传统2PC中各自本地分支事务持有的数据库资源锁都要保持到“提交阶段”完成后才被释放,而Seata则是在“准备阶段”就将本地分支事务提交了,避免了在提交阶段长期持有数据库资源锁的问题
- TCC
要求每个本地分支事务必须实现以下3个操作:Try(预处理 ,业务检查及资源预留)、 Confirm(确认操作)、Cancel(取消操作),三个阶段都需要开发者编写相关的业务代码来实现,开发成功较高,如果Confirm、Cancel操作失败还需要人为编写业务代码进行重试(幂等处理) - 最终一致(RocketMQ消息中间件)和最大努力通知
1、本地订单持久化之前,先发送一个扣减库存的半事务消息给RocketMQ,RocketMQ收到半事务消息后并做出成功响应
2、本地事务收到成功响应后开始提交订单:
2.1、订单提交失败,本地事务告知RocketMQ结果,RocketMQ对该消息进行周期性存储
2.2、订单提交成功,本地事务告知RocketMQ结果,RocketMQ对扣减库存的半事务消息进行投递
2.3、由于网络等其它原因,RocketMQ一直没有收到本地订单的提交结果通知,则会主动发起本地订单状态回查(需要开发者提供相关接口),根据回查结果决定是否对扣减库存的半事务消息进行投递
3、如果扣减库存的半事务消息执行失败了,则触发重新投递,超过指定次数后进入死性队列进行周期性存储,针对死性队列的数据需要人为干预
最大努力通知需要开发者自定义相关表来存储失败消息以保证被下游系统消费,开发成本高,代码耦合大