分布式事务的有关思考
2018-01-24 15:58
295 查看
首先从一个问题入手,在本人实际工作中,为实现一项功能,有以下事务操作:
在没有进行数据库拆库前,A表和B表都属于同一个库,这项功能只要保证在一个事务中执行即可。但进行数据库拆库后,A和B属于不同的数据库,需要对上面的代码进行改造,操作B时需要通过远程调用实现。虑以下几种情况:
1,需要明确知道调用B的结果后A才能返回,即A对B强依赖:A的操作完成后,设置一个中间状态,然后提交事务,远程调用B成功后,更新这个中间状态,返回成功,其伪代码大致如下:
下面针对上面的伪代码思考几个问题:
a,如果执行A的事务操作过程中系统A崩溃或者异常了,这时事务还没有提交,返回失败,数据正常!
b,如果A事务执行成功后,系统A崩溃,如何处理?这种情况下,需要通过补偿job定时扫描这个中间状态标志位,回滚A的操作,然后更新其标志位状态为失败。这里有个问题,正常的操作(调用B之前)也可能被这个job扫描出来,为了避免这种情况,需要引入一个时间戳。job只扫描时间戳与当前时间间隔一定范围的数据。
c,如果调用B的过程中,系统A挂了,如何处理?这种情况下首先同b,由补偿job去扫描这个中间状态,不同的是首先得调用B的撤销接口(因为不知道此时B的状态,统一撤销掉),如果撤销成功,执行A的回滚操作,再更新中间标志位为失败。如果调用撤销接口失败,重试。如果更新标志位过程中或者回滚过程中出现异常,重试,但此时需要B的撤销接口支持幂等!所以这种情况下,需要B的撤销接口有以下功能,如果没有对应的记录,需要返回撤销成功,同时要支持幂等!
d,如果网络异常,撤销B的操作失败了,如何处理?此时返回失败,由补偿job去执行,同c。如果回滚A,update中间出现了异常,依靠job,同c。
e,如果撤销B的操作代价很大,可能耗时比较长,同时远程同步调用B的撤销接口还得处理下接口的异常以及网络超时,放在此处影响性能,如何处理?撤销B的操作改为发送MQ消息,由B进行消费。一般来说我们把消息到MQ中间件,由中间件来保证消费成功。只要发送MQ消息成功,即可执行下一步操作。如果此时发送MQ异常,则交由job去重试,捞出中间状态的数据,执行发送mq和回滚A,update中间状态的操作,此时需要B接口支持米等!
2,A对B的依赖性不是那么强,比如A系统操作完成后,需要将变更的数据同步给系统B,此时如何处理?
系统A先执行事务操作,在这个事务中,将要变更的数据写入到数据表中,置一个状态,由job定时将数据同步给B,同步成功后,更新状态。
3,假如A要完成的功能很复杂,存在这样的调用链A----->B----->C----->D----->E---->F---->G,其中G之前的都成功了,调用G的时候失败了,这时如果直接依次调用各个系统的撤销接口,代价是很大的,如何处理?
采用发送mq消息和job结合的处理方式,这是所有提供撤销接口的系统都需要支持米等!
public Object transactionMethod(){ A.operate1(); A.operate2(); B.operate(); return success; }
在没有进行数据库拆库前,A表和B表都属于同一个库,这项功能只要保证在一个事务中执行即可。但进行数据库拆库后,A和B属于不同的数据库,需要对上面的代码进行改造,操作B时需要通过远程调用实现。虑以下几种情况:
try{ begin transaction; A.operate1 A.operate2//这一步置中间状态标志位 commit transaction; }catch(Exception e){ rollback; return fail; } try{ if(call remote B success){ update 中间状态标志位置成功 return success; }else{ 回滚A,update 中间状态标志位置失败(事务操作) return fail; } }catch Exception(Exception e){ //走到这里一般来说是网络异常了 撤销B的操作(由于此时不知道B是否已经进行了修改) 回滚A,update中间状态标志位置失败(事务操作) return fail; }
1,需要明确知道调用B的结果后A才能返回,即A对B强依赖:A的操作完成后,设置一个中间状态,然后提交事务,远程调用B成功后,更新这个中间状态,返回成功,其伪代码大致如下:
下面针对上面的伪代码思考几个问题:
a,如果执行A的事务操作过程中系统A崩溃或者异常了,这时事务还没有提交,返回失败,数据正常!
b,如果A事务执行成功后,系统A崩溃,如何处理?这种情况下,需要通过补偿job定时扫描这个中间状态标志位,回滚A的操作,然后更新其标志位状态为失败。这里有个问题,正常的操作(调用B之前)也可能被这个job扫描出来,为了避免这种情况,需要引入一个时间戳。job只扫描时间戳与当前时间间隔一定范围的数据。
c,如果调用B的过程中,系统A挂了,如何处理?这种情况下首先同b,由补偿job去扫描这个中间状态,不同的是首先得调用B的撤销接口(因为不知道此时B的状态,统一撤销掉),如果撤销成功,执行A的回滚操作,再更新中间标志位为失败。如果调用撤销接口失败,重试。如果更新标志位过程中或者回滚过程中出现异常,重试,但此时需要B的撤销接口支持幂等!所以这种情况下,需要B的撤销接口有以下功能,如果没有对应的记录,需要返回撤销成功,同时要支持幂等!
d,如果网络异常,撤销B的操作失败了,如何处理?此时返回失败,由补偿job去执行,同c。如果回滚A,update中间出现了异常,依靠job,同c。
e,如果撤销B的操作代价很大,可能耗时比较长,同时远程同步调用B的撤销接口还得处理下接口的异常以及网络超时,放在此处影响性能,如何处理?撤销B的操作改为发送MQ消息,由B进行消费。一般来说我们把消息到MQ中间件,由中间件来保证消费成功。只要发送MQ消息成功,即可执行下一步操作。如果此时发送MQ异常,则交由job去重试,捞出中间状态的数据,执行发送mq和回滚A,update中间状态的操作,此时需要B接口支持米等!
2,A对B的依赖性不是那么强,比如A系统操作完成后,需要将变更的数据同步给系统B,此时如何处理?
系统A先执行事务操作,在这个事务中,将要变更的数据写入到数据表中,置一个状态,由job定时将数据同步给B,同步成功后,更新状态。
3,假如A要完成的功能很复杂,存在这样的调用链A----->B----->C----->D----->E---->F---->G,其中G之前的都成功了,调用G的时候失败了,这时如果直接依次调用各个系统的撤销接口,代价是很大的,如何处理?
采用发送mq消息和job结合的处理方式,这是所有提供撤销接口的系统都需要支持米等!
相关文章推荐
- Percolator与分布式事务思考
- 分布式事务两阶段提交(2PC)的思考
- 分布式事务一些总结与思考
- 分布式事务的总结与思考
- 从银行转账失败到分布式事务:总结与思考
- 从银行转账失败到分布式事务:总结与思考 - 转
- DBCC大全集之(适用版本MS SQLServer 2008 R2)----DBCC OPENTRAN如果在指定数据库内存在最早的活动事务和最早的分布式和非分布式复制事务,则显示与之有关的信息
- 分布式事务一些总结与思考
- 微服务分布式事务的一些思考
- 有关公司分布式架构的思考
- 微服务分布式事务的一些思考
- 分布式事务:总结与思考
- 分布式事务的思考
- 从银行转账失败到分布式事务:总结与思考
- 从银行转账失败到分布式事务:总结与思考
- 微服务分布式事务的一些思考
- 从银行转账失败到分布式事务:总结与思考
- php处理分布式事务的思考(转)
- 从银行转账失败到分布式事务:总结与思考
- 从银行转账失败到分布式事务:总结与思考