罗列分布式事务解决方案
1、本地消息表
以订单成功之后扣减库存为例,通过记录一条扣减库存的记录和发送一条消息来保证两个服务之间数据的最终一致性。
(1)优点:实现逻辑简单,开发量小
(2)缺点:与业务强耦合;占用业务系统资源;业务使用场景有限
2、RocketMQ事务消息
以订单下单成功之后增加积分为例,通过RocketMQ事务消息实现数据的最终一致性
(1)优点:中间件已经实现了事务逻辑,无需增加额外的配置开发
(2)缺点:实时性不可以保证;业务最终一定要成功;事务消息部分代码未开源
3、seata的AT模式
AT模式是对分布式事务理论的二阶段提交协议的改进,此模式的代码侵入性小(只需导入jar)、操作方便,由于事务协调器(TC)会持久化分支事务的状态,事务的分支id在事务执行成功会被标记成为已经成功的状态,其他没有标记成功的分支事务会TC的定时器继续通知。保证了所有分支的事务最终的一致性。
AT模式的缺点:只适用与关系性的数据库(如A服务Mysql和B服务redis/es之间的事务就不支持)
4、seata的TCC模式
由于AT模式存在一些业务场景不适用,所以出现了seata-TCC模式,下图是官方的TCC模式工作原理图:
官方给的原理图比较抽象,我们通过下单的案例分析TCC模式的工作原理:
(1)try阶段
服务 | 职责 |
---|---|
红包服务 | 扣减红包中的支付金额,增加一条记录来记录本次扣减多少钱 |
积分服务 | 不用操作(加操作一定是可以成功的,哪怕是一小时之后的执行成功) |
订单服务 | 将订单状态修改成支付中,防止其他线程修改成交易超时取消或者取消订单 |
(2)confirm阶段
服务 | 职责 |
---|---|
红包服务 | 不需要操作,因为钱已经扣除了 |
积分服务 | 增加积分 |
订单服务 | 将订单状态修改成已经支付 |
(3)cancel阶段
服务 | 职责 |
---|---|
红包服务 | 查询直接的支付记录获取扣了多少钱,给红包账户增加对应的金额 |
积分服务 | 不需要操作 |
订单服务 | 将订单状态修改成支付失败 |
TCC模式下的几种异常处理
(1)TCC异常处理-空回滚
订单服务调用积分服务的时候,由于网络抖动的原因没请求成功,TC就会通知服务执行回滚操作。但是积分服务没有执行try就直接执行cancel,导致业务中用户的积分增加这就是空回滚。
处理方案:增加一个日志表来记录是否执行try方法,如果没有执行try,那么cancel也不执行
(2) TCC 异常处理-幂等性
二阶段的方法被多次的调用(二阶段会有定时器不断的重试)这就是存在幂等性问题。
处理方案:积分服务的业务上需要做幂等(如使用状态机来处理)
(3) TCC 异常处理-防悬挂
服务做完try资源被预留出来,但是TC通知积分cancel空回滚且立即执行完成(假设cancel比try先执行完),整个事务就结束了。实际业务要给用户增加了积分就无法回滚。
处理方案:在日志表中增加cancel、try的记录,如果try存在记录,那么cancel操作就先失败等待下次执行。
以上就是常见的分布式事务的解决方案,希望对大家有帮助。