理解分布式事务

Posted 嗨小叔的程序猿之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解分布式事务相关的知识,希望对你有一定的参考价值。

    昨天讲了《 》,鉴于帅气小黑的建议,从网上整理了一些通俗易懂的分布式事务方面知识点,由于每周有两三天的加班,所以更新会很晚或者断更的情况,望见谅!


面试问答

问:分布式事务场景如何设计系统架构及解决数据一致性问题?
参考答:把握以下原则:大事务=小事务(原子事务)+异步(消息通知),解决分布式事务的最好办法其实就是将一个大的业务进行拆分,整个大的业务流程,转化成若干个小的业务流程,然后通过设计补偿流程从而考虑最终一致性。


一、定义

    百度百科:分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

    简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。

    本质上来说,分布式事务就是为了保证不同数据库的数据一致性。(分布式事务只需要保证了原子性,这个原子性也保证了应用层面的一致性,而由本地事务来保证隔离性和持久性。)

二、常见的分布式事务应用场景及解决方案

柔性事务实现方式有四种分别针对不同的业务场景:

  • 两阶段型

  • 补偿型

  • 异步确保型

  • 最大努力通知型

(以下场景基于此图来做说明)

场景一、库存数量与订单数量一致性

      采用补偿型+最大努力通知型,采用原因为不涉及跨机房和长事务(正常情况下库存与订单服务处理很快):
1、用户下单先减库存
2、库存减成功后,调用下单服务
3、若下单成功,两事务均提交完成;若下单失败,库存回滚,两事务均失败,此处还有一个保障机制(最大努力通知型),就是如果调用库存服务异常,确定库存回滚失败了,则放入消息服务(延时消息队列)分阶段定时重试,努力重试保证库存服务正常后成功回滚。

场景二、订单信息、支付信息、充值信息三者之间的一致性

    采用异步确保型。主要原因是整个业务链路太长且跨不同的机房系统,网络延迟较高,业务方面恰好不需要非常高的实时性,所以采用小事务+异步通知,

    目前正常情况下用户从下单到完成支付到流量到账平均为1-5分钟左右。

    1、下单成功即订单服务创建订单成功并发送支付请求到支付网关系统(订单状态-待支付,超过1小时未支付则流转为超时未付撤销,此处用到了RocketMQ的延时消费恰好实现定时器业务场景)。
    2、返回支付页面,用户在支付交易系统完成支付业务流程,支付网关异步通知流量中心,流量中心接收到支付成功状态后修改订单状态-支付成功,并给支付网关返回成功结果。
    3、流量中心修改完订单状态后,调用消息服务将直充业务放入消息队列,对直充业务进行解耦(原因是直充需要调用31省移动CRM系统,此链路过长,且部分省CRM系统耗时非常大,每个省的处理能力不同,经常出现20秒以上的超时,因此要考虑部分超时较高的省份拖垮系统,进行业务的削峰填谷);
    4、若当直充成功时,修改订单状态-已完成;若当直充失败时(移动特性,例如:直充时正好用户销户或者停机了),修改订单状态为待退款,并调用支付网关系统的退款接口,退款成功后支付网关异步通知流量中心,流量中心修改订单状态为-退款成功;
     5、当直充超时时,调用定时任务服务进行超时重试机制(第一次重试在10分钟后执行、第二次在30分钟后、第三次…..),直到最大超时重试次数后还得不到直充结果,订单状态会卡在支付成功状态,依赖T+1对账稽核流程保证最终一致性,订单状态根据对账结果流转为:已完成或待退款–>退款成功。

场景三、直充到账后的消息通知(APP消息推送或短信通知)

    采用最大努力通知型,这个业务场景比较简单,在直充成功后,订单状态流转为已完成,此时通过消息服务进行到账通知业务的解耦,调用消息服务失败的情况下,使用定时任务努力通知。

场景四、直充到账后的消息通知(APP消息推送或短信通知)

(1)、对账稽核:
    按照支付账期每日进行T+1对账,对账原则:以支付交易记录为准,对流量中心订单记录+支付网关交易记录+省CRM充值记录三方比对,将某些中间状态的订单(例如:支付成功、待退款)核对后将订单状态流转完结(已完成、退款成功)。
(2)、结算稽核:
    对账成功后的数据定期进入结算流程,对支付网关周期内的支付金额与结算数据的金额进行核对,稽核成功后进行财务结算流程,将钱结算给省公司,并提供结算明细给省公司,供省公司与直充成本记录进行复核。

拆分原则遵循下图:

理解分布式事务

  场景五、基于XA协议的两阶段提交

    XA是一个分布式事务协议,由Tuxedo提出。

    XA中大致分为两部分:事务管理器和本地资源管理器。

    其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。

    XA实现分布式事务的原理如下:

    

理解分布式事务

    总的来说,XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。但是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,往往并发量很高,XA无法满足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回导致主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得非常狭隘。

三、总结
    分布式事务,本质上是对多个数据库的事务进行统一控制,按照控制力度可以分为:不控制、部分控制和完全控制。

    不控制就是不引入分布式事务,部分控制就是各种变种的两阶段提交,包括消息事务+最终一致性、TCC模式,而完全控制就是完全实现两阶段提交。(所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,如果更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,复杂度也不一样,因此,这种模式并不能很好地被复用。

    部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了。

    完全控制则是牺牲了性能,保障了一致性。

    具体用哪种方式,最终还是取决于业务场景。作为技术人员,一定不能忘了技术是为业务服务的,不要为了技术而技术,针对不同业务进行技术选型也是一种很重要的能力!


    无论你从什么时候开始,

    重要的是开始后就不要停止,

    无路你从什么时候结束,

    重要的是结束后就不要悔恨!

    晚安!理解分布式事务理解分布式事务理解分布式事务


以上是关于理解分布式事务的主要内容,如果未能解决你的问题,请参考以下文章

深入理解分布式事务,高并发下分布式事务的解决方案

理解分布式事务

深入理解分布式事务,高并发下分布式事务的解决方案

还不理解“分布式事务”?这篇给你讲清楚!

深入理解分布式事务,高并发下分布式事务的解决方案

深入理解分布式事务