首页 > 其他 > 详细

关于分布式事务问题的一些思考

时间:2016-03-28 02:20:28      阅读:405      评论:0      收藏:0      [点我收藏+]

周末的技术分享会上某位同事分享的一个案例牵扯出了分布式事务的问题,引发了我的一些思考,这里记录一下。

?

现有的生产环境中核心业务现在分成三个项目,姑且叫A、B、C吧。A负责日常营业相关的前台入口,比如用户注册登记、下订单等等;B负责后台系统管理人员的资料维护,日常业务数据统计等;C是衍生出来的项目,就是把原有A、B中涉及的共通的业务抽取出来,形成的一个Core项目,包括了用户、账户、商品相关业务等。因为随着业务访问量的上升,原有的业务表和逻辑会不断扩充,数据量也不断增加,再突破单机容量极限之前项目肯定会拆分来开发、部署、实施。

?

问题就产生在这种拆分的情况下,比如,原有的下订单的逻辑直接在A项目中的一个Controller层调用一个服务,几张业务表(比如商品扣减库存、扣减账户余额,生成相关订单)搞定了,所有事务交给A项目的Spring框架的事务管理搞定,期间调用相关业务服务的某次失败(比如恰好在下单瞬间用户余额不足或库存不够了)会使得整个事务回滚(这点Spring的事务管理器做的已经很出色)。

?

但现在将项目拆分开来,项目和项目之间是分开部署,它们之间的调用走的是RPC,所以原来一个下订单的服务(AOrderService.method)涉及了本身A项目里面的服务和C项目里面的服务的调用,比如这个场景涉及AService.method1、AService.method2、CService.method3、AService.method4。假如AService.method1、AService.method2、CService.method3执行成功、AService.method4执行失败,怎么办?因为AService.method4执行失败了,会抛出异常,而且AService.method1、AService.method2、AService.method4同在一个项目中,所以事务框架会自动回滚前面执行的SQL,可是CService.method3是在C项目中,其事务是单独维护的,这次请求调用它的执行是成功的,所以C项目中事务已经提交了。

?

针对这个问题的解决方式我想到了三种:

1.把AService.method1、AService.method2、AService.method4这三个服务也抽出来放到C项目中,使这些方法始终在一个项目中,从而规避了事务的分布式困扰。这个对业务限制太大,久而久之将形成一个薄的Controller层A项目和巨无霸臃肿的C项目。

?

2.如果CService.method3和AService.method4之间没有执行上的前后依赖关系的话,把CService.method3挪到整个AOrderService的方法最后调用。这是种打补丁的做法,现在勉强可用,后续扩展开来没发搞,比如再增加一个B项目的服务调用还是会出问题。

?

3.搬出分布式事务问题的学院式解法:两阶段提交(XA),Java针对这个规范提供了JTA的解决方案,这个可以倒是可以,但是太重,并且延迟和并发上难以忍受。

?

4.事务补偿。即通过实时消息来解耦不同项目间的调用,其间一旦发现项目的调用失败了会反过来通知整个业务链,使得整个业务回滚。这好像是此问题的一般做法了,但它要求所有这些业务接口满足两个条件:业务接口的调用是幂等的,业务接口都存在反向的逆操作接口。

?

5.事务补偿的变通形式,即定时任务扫业务表,发现失败自动执行脚本回滚业务,这种方案是异步并有一定延迟的,并且前提是项目足够小,不然这脚本做出来都很复杂难懂。

?

?

关于分布式事务问题的一些思考

原文:http://tyrion.iteye.com/blog/2286652

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!