[转帖]如何选择分布式事务形态(Fescar、TCC、SAGA、补偿、基于消息的最终一致

如何选择分布式事务形态(Fescar、TCC、SAGA、补偿、基于消息的最终一致

https://blog.csdn.net/zhangjunli/article/details/100015236

各种形态的分布式事务
分布式事务有多种主流形态,包括:

基于消息实现的分布式事务
基于补偿实现的分布式事务
基于TCC实现的分布式事务
基于SAGA实现的分布式事务
基于2PC实现的分布式事务
这些形态的原理已经在很多文章中进行了剖析,用“分布式事务”关键字就能搜到对应的文章,本文不再赘述这些形态的原理,并将重点放在如何根据业务选择对应的分布式事务形态上。

何时选择单机事务?
这个相信大家都很清楚,在条件允许的情况下,我们应该尽可能地使用单机事务,因为单机事务里,无需额外协调其他数据源,减少了网络交互时间消耗以及协调时所需的存储IO消耗,在修改等量业务数据的情况下,单机事务将会有更高的性能。

但单机数据库由于 业务逻辑解耦等因素进行了数据库垂直拆分、或者由于单机数据库性能压力等因素进行了数据库水平拆分之后,数据分布于多个数据库,这时若需要对多个数据库的数据进行协调变更,则需要引入分布式事务。

分布式事务的模式有很多种,那究竟要怎么选择适合业务的模式呢?以下我们将从使用场景、性能、开发成本这几个方面进行分析。

何时选择基于消息实现的事务?
基于消息实现的事务适用于分布式事务的提交或回滚只取决于事务发起方的业务需求,其他数据源的数据变更跟随发起方进行的业务场景。

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

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

从这个过程可以看到,基于消息队列实现的事务存在以下操作:

订单服务创建订单,提交本地事务
订单服务发布一条消息
积分服务收到消息后加积分
我们可以看到它的整体流程是比较简单的,同时业务开发工作量也不大:

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

何时选择利用补偿实现的事务?
但是基于消息实现的事务并不能解决所有的业务场景,例如以下场景:某笔订单完成时,同时扣掉用户的现金。

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

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

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

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

(题外话:阿里GTS也是利用补偿实现,只不过补偿代码自动生成,无需业务干预,同时接管应用数据源,禁止业务修改处于全局事务状态中的记录。)

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

这时我们可以引入TCC,其流程如下:

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

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

订单服务编写创建订单的逻辑
现金服务编写冻结现金的逻辑
现金服务编写扣除现金的逻辑
现金服务编写解冻现金的逻辑
TCC实际上是最为复杂的一种情况,其能处理所有的业务场景,但无论出于性能上的考虑,还是开发复杂度上的考虑,都应该尽量避免该类事务。

何时选择利用SAGA实现的事务?
SAGA可以看做一个异步的、利用队列实现的补偿事务。

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

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

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

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

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

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

但当然SAGA也可以进行稍微改造,变成与TCC类似、可以进行资源预留的形态。

2PC事务
其适用于参与者较少,单个本地事务执行时间较少,并且参与者自身可用性很高的场景,否则,其很可能导致性能下降严重。

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

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

由于前期只采用了其中一种类型事务的框架,因为工具目前只有锤子,引入其他工具又涉及测试、阅读代码等过程,因此把所有问题都看做钉子,导致性能偏低或者实现不够优雅
由于不同框架管理事务的形态可能不一致,导致不能很好的协调工作,如某一个TCC框架和另一个基于消息的事务框架无法很好融合。
解决方案
为了解决上面提到的问题,EasyTransaction这个基于Spring的分布式事务框架,实现了上述除2PC以外的所有事务形态,并提供了统一的使用接口,完美地解决了以上的问题。其主要特性如下:

一个框架包含多种事务形态,一个框架搞定所有类型的事务
多种事务形态可混合使用
高性能,若不启用框架的幂等功能,对业务数据库的额外消耗仅为写入25字节的一行
可选的框架幂等实现(包括调用次序错乱处理),大幅减轻业务开发工作量
业务代码可实现完全无入侵
支持嵌套事务
无需额外部署协调者,不同APP的服务协调自身发起的事务
分布式事务ID可关联业务ID,业务类型,APPID,便于监控各个业务的分布式事务执行情况
若各位对ET兴趣,可以到 https://github.com/QNJR-GROUP/EasyTransaction 查看详细介绍及示例,本文不再深入介绍

总结
不同业务场景应按需引入不同的事务形态,在条件允许的情况下,个人建议按照如下次序选择对应的事务形态:

单机事务》基于消息的事务》基于补偿的事务》TCC事务
因SAGA事务的形态需要配合较为明显的前端业务交互变更,个人建议在单一事务执行过程较长、存在较多子事务,并且无法使用基于消息的事务形态时使用。
————————————————
版权声明:本文为CSDN博主「zhangjunli」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhangjunli/article/details/100015236

原文地址:https://www.cnblogs.com/jinanxiaolaohu/p/12091767.html

时间: 2024-10-05 04:55:53

[转帖]如何选择分布式事务形态(Fescar、TCC、SAGA、补偿、基于消息的最终一致的相关文章

分布式事务解决(5):可靠消息的最终一致性方案-消息重复发送问题与业务接口的幂等性设计

一.消息消费流程的异常分析与处理 1.1.消息消费流程的异常点 1.2.消息消费流程的异常处理 方法:对于未确认的消息,采用按规则重新投递的方式进行处理. 问题:消息的重复发送会导致业务处理接口出现重复调用的问题. 未完,待续....

分布式事务中间件 Fescar—RM 模块源码解读

前言在SOA.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用回滚的系统设计一直是个难点.我所在的团队也遇到了这个问题,为解决这个问题上,团队采用的是阿里开源的分布式中间件Fescar的解决方案,并详细了解了Fescar内部的工作原理,解决在使用Fescar中间件过程中的一些疑虑的地方,也为后续团队在继续使用该中间件奠定理论基础. 目前分布式事务解决方案基本是围绕两阶段提交模式来设计的,按对业务是有侵入分为:对业务无侵入的基于XA协议

阿里开源分布式事务解决方案 Fescar 全解析

广为人知的阿里分布式事务解决方案:GTS(Global Transaction Service),已正式推出开源版本,取名为"Fescar",希望帮助业界解决微服务架构下的分布式事务问题,今天我们一起来深入了解. FESCAR on GitHub https://github.com/alibaba/fescar 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,系统微服务化后,一个看似简单的功能,

分布式事务(第05篇)分布式事务解决方法-TCC

一 什么是TCC TCC将每个分支事务都分成三个部分(Try.Confirm.Cancel): Try:业务检查及资源预留. Confirm:真正执行业务,不做任何业务检查.使用Try阶段预留的资源. Cancel:实现回滚操作,释放资源. 二 TCC实现分布式事务的流程 第一阶段:全局事务管理器分别调用所有分支事务,所有分支事务进行Try操作,当所有分支事务的Try操作都成功,或者某部分分支事务的Try操作失败,都进入第二阶段. 第二阶段:如果第一阶段所有分支事务Try都成功执行,则全局事务管

转: 分布式事务:不过是在一致性、吞吐量和复杂度之间,做一个选择

from:  http://mp.weixin.qq.com/s?__biz=MzA5Nzc4OTA1Mw==&mid=2659598134&idx=1&sn=f5f73354d162a7561b3d73c204a4d1f5&scene=0#wechat_redirect 这是一个开撕的话题,我经历过太多的关于分布式事务的需求:“有没有简单的方案,像使用数据库事务那样,解决分布式数据一致性的问题”.特别是微服务架构流行的今天,一次交易需要跨越多个“服务”.多个数据库来实现,

java分布式事务

原文地址:http://blog.csdn.net/moonpure/article/details/52779794 在本系列先前的文章中,我们主要讲解了JDBC对本地事务的处理,本篇文章将讲到一个分布式事务的例子. 请通过以下方式下载github源代码: git clone https://github.com/davenkin/jta-atomikos-hibernate-activemq.git 本地事务和分布式事务的区别在于:本地事务只用于处理单一数据源事务(比如单个数据库),分布式事

Java事务处理全解析(八)——分布式事务入门例子(Spring+JTA+Atomikos+Hibernate+JMS)

在本系列先前的文章中,我们主要讲解了JDBC对本地事务的处理,本篇文章将讲到一个分布式事务的例子. 请通过以下方式下载github源代码: git clone https://github.com/davenkin/jta-atomikos-hibernate-activemq.git 本地事务和分布式事务的区别在于:本地事务只用于处理单一数据源事务(比如单个数据库),分布式事务可以处理多种异构的数据源,比如某个业务操作中同时包含了JDBC和JMS或者某个操作需要访问多个不同的数据库. Java

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

这两天正在研究微服务架构中分布式事务的处理方案, 做一个小小的总结, 作为备忘. 如有错误, 欢迎指正! 概念澄清 事务补偿机制: 在事务链中的任何一个正向事务操作, 都必须存在一个完全符合回滚规则的可逆事务. CAP理论: CAP(Consistency, Availability, Partition Tolerance), 阐述了一个分布式系统的三个主要方面, 只能同时择其二进行实现. 常见的有CP系统, AP系统. 幂等性: 简单的说, 业务操作支持重试, 不会产生不利影响. 常见的实现

从银行转账失败到分布式事务:总结与思考

目录 关系型数据库事务 分布式事务 2PC 3PC TCC 基于消息的分布式事务 1PC 思考与总结 references 正文 思考这个问题的初衷,是有一次给朋友转账,结果我的钱被扣了,朋友没收到钱.而我之前一直认为银行转账一定是由事务保证强一致性的,于是学习.总结了一下分布式事务的各种理论.方法. 事务是一个非常广义的词汇,各行各业解读都不一样.对于程序员,事务等价于Transaction,是指一组连续的操作,这些操作组合成一个逻辑的.完整的操作.即这组操作执行前后,系统需要处于一个可预知的