这篇文章将介绍分布式事务中的多种实现方案,及各种分布式事务方案的实现原理、事务执行过程、优缺点,读完这篇文章相信你会对2PC、3PC、TCC、MQ事务消息有个详细的了解
分布式事务的处理方法有哪些?
XA协议:基于分布式事务协议,主要由事务管理器和本地资源管理器组成,事务管理器是一个全局调度者,负责本地资源管理器统一的提交或回滚事务。mysql、oracle均已支持XA协议
2PC(两阶段提交)
基本流程:
Prepare预备阶段
:预执行需要执行的sql,但不提交事务Commit提交阶段
:提交事务
不足:
- 数据不一致:在事务管理器向所有服务发送提交事务Commit阶段时,某些参与者可能发生网络抖动,无法正常接收到Commit请求,从而导致每个参与者的数据不一致
- 超时导致同步阻塞:当有一个参与者出现通信超时,其余所有参与者将一直阻塞无法释放资源
- 单点故障风险:如图可知,资源管理器统一协调所有参与者,一旦资源管理器出现故障,则参与者无法完成Commit操作,会一直处于阻塞状态。尽管资源管理器会重新选举,当还是无法解决之前遗留的阻塞问题。
- 性能问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈
3PC(三阶段提交)
基本流程:
CanCommit
:协调者向所有参与者发送CanCommit命令,,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段PreCommit
:预提交事务操作,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回Yes响应,进入最终commit阶段。一旦参与者中有向协调者发送了No响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送abort请求,参与者接受abort命令执行事务的中断。DoCommit
:前两个阶段都返回YES响应后,协调者向参与者发送DoCommit正式提交事务命令,如果没有接收到ACK响应,则向其它参与者发送abort命令,执行事务中断
相对于2PC的改进:
- 在协调者与参与者加入了超时机制,当在一定时间内未收到协调者的commit请求,会自动提交事务,不会一致阻塞等待
- 3PC将2PC的Prepare准备阶段拆分为 2 个阶段,插入了一个 ==PreCommit ==阶段,解决原先在2PC中,由于协调者发生故障而导致参与者无法知晓是否commit或abort的状态而产生的相当长的阻塞问题得以解决
- 有了自动提交事务,一旦发生单点故障,事务也可以自动提交
不足:
- 在发送abort命令的时候,如果因为网络原因部分参与者没有接收到请求,还是会导致数据不一致性问题
TCC(事务补偿)
TCC也是实现分布式事务的一种方案,不过它是属于应用层面的,非基于XA协议,需要我们编写业务代码来实现类似于2PC的命令功能
核心思想:
对于每一个操作都有其对应的确认(Confirm)和补偿(Cancel)方法,且它们是幂等性的
基本流程:
Try
:通过Try操作来检查、预留需要的库存,比如需要2台iphone12并进行冻结Confirm
:真正执行业务操作,在之前预留的资源基础上完成购买和创建订单Cancel
:在Try阶段预留2台iphone12失败,则取消所有业务资源的预留(也就是恢复try之前)
优点:
- 性能提升:依据业务来控制资源锁的粒度,不会控制整个资源
- 数据最终一致性:基于Confirm和Cancel的幂等性,能够保证事务完成或取消
- 可靠性:解决了XA协议中事务管理器单点故障问题,直接由业务活动发起并控制整个业务活动,业务活动管理器也变成了多点(集群)
不足:
7. 代码侵入性强:之前也说需要在业务层面实现这三个命令,实际就是需要实现三个接口
8. 开发成本高:因为需要自己实现三个阶段的业务代码,开发量很大;且如果要保证数据一致性,需要自己实现幂等性
RocketMQ事务消息(最终一致性)
基本流程:
- 事务主动方向消息集群发送消息,但这个消息不能被消费
- 事务主动方执行本地事务A,执行成功后根据消息地址去修改消息状态为commit或rollback,如果是commit则会被事务被动方消费,否则将删除消息
- 事务被动方读取消息,然后执行本地事务B
- 事务被动方将事务B执行结果返回到MQ Server
- 事务主动方读取接收方事务处理结果
异常情况1:如果事务主动方发送commit or rollback消息失败,未到达消息集群
- 消息集群(MQ Server)会发起消息回查
- 事务主动方收到回查消息后,会检查本地事务的执行结果
- 根据本地事务的执行结果重新发送commit or rollback消息
- MQ Server根据接收到的消息(commit or rollback)判断消息是否可消费或直接删除
异常情况2:接收方消费失败或消费超时
一直重试消费,直到事务被动方消费消息成功,整个过程可能会导致重复消费问题,所以业务逻辑需要保证幂等性
异常情况3:消息已消费,但接收方业务处理失败
通过MQ Server通知发送方进行补偿或事务回滚
优点:
- 系统解耦:消息之间独立存储,系统之间消息完成事务
- 复杂度低,实现简单
缺点:
- 一次消息需要发送两次请求(half消息+commit or rollback)
- 业务中需要实现消息状态回查接口
Spring中已经有了事务,还需要使用事务消息吗?
如果是在Spring框架下,可以将发送消息的逻辑绑定到本地事务中,发消息失败就抛出异常,回滚事务,以此来保证本地事务与发送消息的原子性
参考
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/17855.html