分布式事务问题

最近在项目中遇到一个分布式事务问题,跟平常的情况不太一样,特此记录一下。

正常事务执行情况

正常情况下一个分布式调用过程如下:

 

这种情况下的回滚:

如果方法C执行失败,需要回滚B;如果D执行失败,需要回滚B和C。

本地方法的回滚,可以抛异常回滚,也可以手动调spring的方法回滚。

远程方法的回滚,可以手动调提供方提供的回滚方法,也可以使用事务消息。

事务消息相对复杂一些,这里介绍一下事务消息的执行过程:

 

 

事务消息需要提供两个接口:

本地事务执行接口:根据事务执行情况返回3种状态:Commit、Rollback、UNKNOW。

本地事务状态查询接口:如果本地事务执行超时,或返回UNKNOW,MQ服务器调用该接口轮询事务状态。

本项目中的事务情况

上面介绍的是一个正常的分布式事务调用情况,但是在本项目中情况稍微复杂一点。原因是本地方法C存在嵌套调用情况,并且最底层的嵌套方法中引入了一个新的远程方法E的调用,同时嵌套的各层方法又被其他方法调用,散落在各个地方,使得方法E的回滚变得比较困难。

本项目中的情况:

 

这种情况下,在方法A、F、G、H中如果后续方法执行失败想要回滚方法E,会比较麻烦。原因是,像方法H这种直接调用方法C2的情况,回滚还稍微容易一点,因为跟方法E相关的上下文可能还保留的比较好,比较好回滚。但是像方法F这种调用方法C的情况,距离方法E的上下文比较远,想要回滚比较麻烦。

总结起来复杂的原因:

  1. 调用嵌套方法的地方很多,如果找不全容易出bug;
  2. 调用嵌套方法的地方距离远程方法上下文比较远,不容易获取回滚参数;
  3. 嵌套方法的参数和逻辑各不一样,想要通过嵌套方法判断是否要回滚,以及获取回滚参数需要做复杂的校验,增加了额外的逻辑和复杂度;

以上原因叠加起来,使得复杂度成倍增长。

有没有一种办法,尽量保证本地事务执行成功之后,再去执行远程方法,这样的话就不用回滚远程方法了?

除了使用上面介绍的事务消息,保证本地事务执行成功之后,消息接收方才会收到事务消息,执行远程方法。有没有不使用事务消息的方法?可以使用消息队列。

方案如下:

 基本流程:

  1. 生产者发送上下文消息,消息内容包括远程调用参数、消息过期时间;
  2. 消费者收到消息,查询本地事务状态:
    1. 如果本地事务未完成,并且消息未过期,则转发消息给消息队列,过期时间不变;
    2. 如果本地事务未完成,并且消息已过期,则丢弃不再处理;
    3. 如果本地事务已完成,则调用远程方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值