各类分布式事务的实现方式适用的场景

1、事务和分布式事务

单机事务咱们常常看到,分布式事务,通俗点将,就是须要在各个机器上跑的事务,可是事务的每一步都不知道其余步是否成功,可是在业务上又要保证,全部的步骤,要么都成功,要么都不成功。spring

分布式事务实现的方式(干货

  1. 基于消息实现的分布式事务
  2. 基于补偿实现的分布式事务(gts/fescar自动补偿的形式)
  3. 基于TCC实现的分布式事务
  4. 基于SAGA实现的分布式事务
  5. 基于2PC实现的分布式事务

什么时候使用单机事务

这个相信你们都很清楚,在条件容许的状况下,咱们应该尽量地使用单机事务,由于单机事务里,无需额外协调其余数据源,减小了网络交互时间消耗以及协调时所需的存储IO消耗,在修改等量业务数据的状况下,单机事务将会有更高的性能。编程

什么时候选择基于消息实现的事务?

基于消息实现的事务适用于分布式事务的提交或回滚只取决于事务发起方的业务需求,其余数据源的数据变动跟随发起方进行的业务场景。网络

举个例子,假设存在业务规则:某笔订单成功后,为用户加必定的积分。框架

在这条规则里,管理订单数据源的服务为事务发起方,管理积分数据源的服务为事务跟随者。异步

从这个过程能够看到,基于消息队列实现的事务存在如下操做:分布式

订单服务建立订单,提交本地事务 订单服务发布一条消息 积分服务收到消息后加积分 咱们能够看到它的总体流程是比较简单的,同时业务开发工做量也不大:工具

编写订单服务里订单建立的逻辑 编写积分服务里增长积分的逻辑 能够看到该事务形态过程简单,性能消耗小,发起方与跟随方之间的流量峰谷可使用队列填平,同时业务开发工做量也基本与单机事务没有差异,都不须要编写反向的业务逻辑过程。所以基于消息队列实现的事务是咱们除了单机事务外最优先考虑使用的形态。性能

可是如何保证消息的可靠性,是须要咱们处理的。 你们能够看一下这篇文章,: 【spring cloud实现可靠消息一致性】。这位兄弟已经写的很详细了,我就不细说了测试

什么时候选择利用补偿实现的事务?

可是基于消息实现的事务并不能解决全部的业务场景,例如如下场景:某笔订单完成时,同时扣掉用户的现金编码

这里事务发起方是管理订单库的服务,但对整个事务是否提交并不能只由订单服务决定,由于还要确保用户有足够的钱,才能完成这笔交易,而这个信息在管理现金的服务里。这里咱们能够引入基于补偿实现的事务,其流程以下:

建立订单数据,但暂不提交本地事务 订单服务发送远程调用到现金服务,以扣除对应的金额 上述步骤成功后提交订单库的事务 以上这个是正常成功的流程,异常流程须要回滚的话,将额外发送远程调用到现金服务以加上以前扣掉的金额。

以上流程比基于消息队列实现的事务的流程要复杂,同时开发的工做量也更多:

编写订单服务里建立订单的逻辑 编写现金服务里扣钱的逻辑 编写现金服务里补偿返还的逻辑 能够看到,该事务流程相对于基于消息实现的分布式事务更为复杂,须要额外开发相关的业务回滚方法,也失去了服务间流量削峰填谷的功能。但其仅仅只比基于消息的事务复杂多一点,若不能使用基于消息队列的最终一致性事务,那么能够优先考虑使用基于补偿的事务形态。

阿里GTS/fescar本质上也是这补偿的编程模型,只不过补偿代码自动生成,无需业务干预,同时接管应用数据源,禁止业务修改处于全局事务状态中的记录。所以,其关于读场景的适用性,可参考补偿。但其在写的适用场景因为引入了全局事务时的写锁,其写适用性介于 TCC以及补偿之间 。

什么时候选择利用TCC实现的事务

然而基于补偿的事务形态也并不是能实现全部的需求,如如下场景:某笔订单完成时,同时扣掉用户的现金,但交易未完成,也未被取消时,不能让客户看到钱变少了。

这时咱们能够引入TCC,其流程以下:

订单服务建立订单 订单服务发送远程调用到现金服务,冻结客户的现金 提交订单服务数据 订单服务发送远程调用到现金服务,扣除客户冻结的现金 以上是正常完成的流程,若为异常流程,则须要发送远程调用请求到现金服务,撤销冻结的金额。

以上流程比基于补偿实现的事务的流程要复杂,同时开发的工做量也更多:

订单服务编写建立订单的逻辑 现金服务编写冻结现金的逻辑 现金服务编写扣除现金的逻辑 现金服务编写解冻现金的逻辑 TCC其实是最为复杂的一种状况,其能处理全部的业务场景,但不管出于性能上的考虑,仍是开发复杂度上的考虑,都应该尽可能避免该类事务。 因此咱们开发了TCC框架,来对应大多数的业务场景,下一篇写一下TCC

什么时候选择利用SAGA实现的事务?

SAGA能够看作一个异步的、利用队列实现的补偿事务。

其适用于无需立刻返回业务发起方最终状态的场景,例如:你的请求已提交,请稍后查询或留意通知 之类。

将上述补偿事务的场景用SAGA改写,其流程以下:

订单服务建立最终状态未知的订单记录,并提交事务 现金服务扣除所需的金额,并提交事务 订单服务更新订单状态为成功,并提交事务 以上为成功的流程,若现金服务扣除金额失败,那么,最后一步订单服务将会更新订单状态为失败。

其业务编码工做量比补偿事务多一点,包括如下内容:

订单服务建立初始订单的逻辑 订单服务确认订单成功的逻辑 订单服务确认订单失败的逻辑 现金服务扣除现金的逻辑 现金服务补偿返回现金的逻辑 但其相对于补偿事务形态有性能上的优点,全部的本地子事务执行过程当中,都无需等待其调用的子事务执行,减小了加锁的时间,这在事务流程较多较长的业务中性能优点更为明显。同时,其利用队列进行进行通信,具备削峰填谷的做用。

所以该形式适用于不须要同步返回发起方执行最终结果、能够进行补偿、对性能要求较高、不介意额外编码的业务场景。

但固然SAGA也能够进行稍微改造,变成与TCC相似、能够进行资源预留的形态。

2PC事务

其适用于参与者较少,单个本地事务执行时间较少,而且参与者自身可用性很高的场景,不然,其极可能致使性能降低严重。

并不是一种事务形态就能打遍天下 经过分析咱们能够发现,并不存在一种事务形态能解决全部的问题,咱们须要根据特定的业务场景选择合适的事务形态。甚至于有时须要混合多种事务形态才能更好的完成目标,如 上面提到的 订单、积分、钱包混合的场景:订单的成功与否须要依赖于钱包的余额,但不依赖于积分的多少,所以能够混合基于消息的事务形态以加积分 及 基于补偿的事务形态以确保扣钱成功,从而获得一个性能更好,编码量更少的形态。

然而目前不少框架都专一于某单一方面的事务形态,如TCC单独一个框架,可靠消息单独一个框架,SAGA单独一个框架,他们各自独立,容易致使如下问题:

因为前期只采用了其中一种类型事务的框架,由于工具目前只有锤子,引入其余工具又涉及测试、阅读代码等过程,所以把全部问题都看作钉子,致使性能偏低或者实现不够优雅 因为不一样框架管理事务的形态可能不一致,致使不能很好的协调工做,如某一个TCC框架和另外一个基于消息的事务框架没法很好融合。

总结

不一样业务场景应按需引入不一样的事务形态。

相关文章
相关标签/搜索