一、分布式事务概念

大家都知道事务的概念:访问或者更新数据库数据的一个程序执行单元。一个事务是由一组sql语句组成的;且具有ACID特性,即原子性、隔离性、持久性、一致性。
随着分布式微服务的发展,数据库拆分和服务化(SOA),便产生了分布式事务的概念。简单讲,就是服务操作涉及多个数据库。

  • 场景一:最早的分布式事务架构很简单,不涉及服务间的调用,仅仅是服务内操作涉及到对多个数据库的访问。
  • 场景二:一个服务操作需要调用另外一个服务,这时的事务就需要跨越多个服务了。

延伸结合上述两个场景,完成某一个业务功能可能需要横跨多个服务,操作多个数据库。需要操作的资源位于多个资源服务器上,而应用需要保证对于多个资源服务器的数据的操作,要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同资源服务器的数据一致性。


二、CAP理论

1、CAP理论

CAP原理指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。因此在进行分布式架构设计时,必须做出取舍。而对于分布式数据系统,分区容忍性是基本要求,否则就失去了价值。因此设计分布式数据系统,就是在一致性和可用性之间取一个平衡。

  • Consistency,一致性。在分布式系统中的所有数据备份,在同一时刻具有同样的值,所有节点在同一时刻读取的数据都是最新的数据副本。
  • Availability,可用性,好的响应性能。完全的可用性指的是在任何故障模型下,服务都会在有限的时间内处理完成并进行响应。
  • Partition tolerance,分区容忍性。尽管网络上有部分消息丢失,但系统仍然可继续工作。

2、BASE理论

Basically Available(基本可用)、Soft-state( 软状态/柔性事务)、Eventual Consistency(最终一致性)。是基于CAP定理演化而来,是对CAP中一致性和可用性权衡的结果。核心思想:即使无法做到强一致性,但每个业务根据自身的特点,采用适当的方式来使系统达到最终一致性。
BASE理论面向的是大型高可用可扩展的分布式系统,通过牺牲强一致性来获得可用性。ACID是传统数据库常用的概念设计,追求强一致性模型。

  • 基本可用 BA:(Basically Available ): 指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用。但不等价于不可用。
  • 软状态 S:( Soft State): 软状态是指允许系统存在中间状态,并且该中间状态不会影响系统整体可用性。即允许系统在不同节点间副本同步的时候存在延时
  • 最终一致性 E:(Eventually Consistent): 系统中的所有数据副本经过一定时间后,最终能够达到一致的状态,不需要实时保证系统数据的强一致性。

3、刚柔事务

刚性事务它的事务是原子的,要么都成功要么都失败,也就是需要保障ACID理论,
柔性事务只需要保障数据最终一致即可,需要遵循BASE理论。

  • 刚性事务满足ACID理论
  • 柔性事务满足BASE理论(基本可用,最终一致)

柔性事务分为:

  • 两阶段型
  • 补偿型
  • 异步确保型
  • 最大努力通知型。

三、常用分布式事务解决方案

分布式事务解决方案几乎都是柔性事务,常见的有2PC/3PC、TCC、MQ等一致性解决方案,至于工作中用哪种方案,需要根据业务场景选取, 2PC/3PC、TCC 数据强一致性高,而MQ是最终数据一致。

1、XA协议

XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器和资源管理器。其中资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理如下:
在这里插入图片描述XA接口详解

X/Open XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁。事务管理器控制着JTA事务,管理事务生命周期,并协调资源。在JTA中,事务管理器抽象为javax.transaction.TransactionManager接口,并通过底层事务服务(即JTS)实现。资源管理器负责控制和管理实际资源(如数据库或JMS队列)。下图说明了事务管理器、资源管理器,以及典型JTA环境中客户端应用之间的关系:
在这里插入图片描述

2、2PC(两阶段提交协议)

两阶段提交协议(The two-phase commit protocol,2PC)是XA用于在全局事务中协调多个资源的机制。将事务的提交过程分为资源准备和资源提交两个阶段,并且由事务协调者来协调所有事务参与者,如果准备阶段所有事务参与者都预留资源成功,则进行第二阶段的资源提交,否则事务协调者回滚资源.
在这里插入图片描述
缺点:

  • 性能问题:执行过程中,所有参与节点都是事务阻塞性的,当参与者占有公共资源时,其他第三方节点访问公共资源就不得不处于阻塞状态,为了数据的一致性而牺牲了可用性,对性能影响较大,不适合高并发高性能场景。
  • 可靠性问题:2PC非常依赖协调者,当协调者发生故障时,尤其是第二阶段,那么所有的参与者就会都处于锁定事务资源的状态中,而无法继续完成事务操作(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
  • 数据一致性问题:在阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
  • 二阶段无法解决的问题:协调者在发出 commit 消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了,那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

3、3PC三阶段提交(Three-phase commit)

三阶段提交有两个改动点:

  • 在协调者和参与者中都引入超时机制
  • 在第一阶段和第二阶段中插入一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。
  • 所以3PC会分为3个阶段,CanCommit 准备阶段、PreCommit 预提交阶段、DoCommit 提交阶段

流程如下:
在这里插入图片描述在这里插入图片描述
3PC的缺点

  • 与2PC相比,3PC降低了阻塞范围,并且在等待超时后,协调者或参与者会中断事务,避免了协调者单点问题,阶段三中协调者出现问题时,参与者会继续提交事务。
  • 数据不一致问题依然存在,当在参与者收到 preCommit 请求后等待 doCommit 指令时,此时如果协调者请求中断事务,而协调者因为网络问题无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。
  • 2PC和3PC都无法保证数据绝对的一致性,一般为了预防这种问题,可以添加一个报警,比如监控到事务异常的时候,通过脚本自动补偿差异的信息。

4、TCC补偿机制

1、TCC(Try Confirm Cancel)

应用层的两阶段提交,所以对代码的侵入性强其核心思想是:针对每个操作,都要实现对应的确认和补偿操作,也就是业务逻辑的每个分支都需要实现 try、confirm、cancel 三个操作

  • 第一阶段:Try,业务系统做检测并预留资源 (加锁,锁住资源),比如常见的下单,在try阶段,我们不是真正的减库存,而是把下单的库存给锁定住。
  • 第二阶段:根据第一阶段的结果决定是执行confirm还是cancel
    • Confirm:执行真正的业务(执行业务,释放锁)
    • Cancle:是对Try阶段预留资源的释放(出问题,释放锁)

在这里插入图片描述

2、TCC的注意事项

1、允许空回滚

空回滚出现的原因是 Try 超时或者丢包,导致 TCC 分布式事务二阶段的 回滚,触发 Cancel 操作,此时事务参与者未收到Try,但是却收到了Cancel 请求。
所以 cancel 接口在实现时需要允许空回滚,也就是 Cancel 执行时如果发现没有对应的事务 xid 或主键时,需要返回回滚成功,让事务服务管理器认为已回滚。
在这里插入图片描述

2、防悬挂控制

悬挂指的是二阶段的 Cancel 比 一阶段的Try 操作先执行
Try操作由于网络拥堵而超时,导致事务管理器生成回滚,触发 Cancel 接口,但之后拥堵在网络的 Try 操作又被资源管理器收到了。但按照前面允许空回滚的逻辑,回滚会返回成功。所以此时应该拒绝执行空回滚之后到来的 Try 操作,否则会产生数据不一致。
因此我们可以在 Cancel 空回滚返回成功之前,先记录该条事务 xid 或业务主键,标识这条记录已经回滚过,Try 接口执行前先检查这条事务xid或业务主键是否已经标记为回滚成功,如果是则不执行 Try 的业务操作。
在这里插入图片描述

3、幂等控制

由于网络原因或者重试操作都有可能导致 Try - Confirm - Cancel 3个操作的重复执行,所以使用 TCC 时需要注意这三个操作的幂等控制,通常我们可以使用事务 xid 或业务主键判重来控制。

4、TCC方案的优缺点

TCC 事务机制相比于上面介绍的 XA 事务机制,有以下优点:

  • 性能提升:具体业务来实现,控制资源锁的粒度变小,不会锁定整个资源。
  • 数据最终一致性:基于 Confirm 和 Cancel 的幂等性,保证事务最终完成确认或者取消,保证数据的一致性。
  • 可靠性:解决了 XA 协议的协调者单点故障问题,由主业务方发起并控制整个业务活动,业务活动管理器也变成多点,引入集群。

缺点:

  • TCC 的 Try、Confirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开发成本。

5、本地消息表

1、本地消息表的核心思路

将分布式事务拆分成本地事务进行处理。在该方案中主要有两种角色:事务主动方和事务被动方

  • 事务主动发起:方需要额外新建事务消息表,并在本地事务中完成业务处理和记录事务消息,并轮询事务消息表的数据发送事务消息。
  • 事务被动方:基于消息中间件消费事务消息表中的事务。这样可以避免以下两种情况导致的数据不一致性。

在这里插入图片描述

2、本地消息表的优缺点

优点

  • 从应用设计开发的角度实现了消息数据的可靠性,消息数据的可靠性不依赖于消息中间件,弱化了对 MQ 中间件特性的依赖。
  • 方案轻量,容易实现。

缺点

  • 与具体的业务场景绑定,耦合性强,不可公用
  • 消息数据与业务数据同库,占用业务系统资源
  • 业务系统在使用关系型数据库的情况下,消息服务性能会受到关系型数据库并发性能的局限

6、MQ事务消息

1、普通MQ

普通MQ的分布式事务方案本质上是对本地消息表的封装,整体流程与本地消息表一致,唯一不同的就是将本地消息表存在了MQ内部,而不是业务数据库中
在这里插入图片描述

2、RocketMQ事务消息

在本地消息表方案中,保证事务主动方发写业务表数据和写消息表数据的一致性是基于数据库事务,而 RocketMQ 的事务消息相对于普通 MQ提供了 2PC 的提交接口,方案如下:
在这里插入图片描述正常情况:

  1. 发送方向 MQ Server(MQ服务方)发送 half 消息
  2. MQ Server 将消息持久化成功之后,向发送方 ack
  3. 确认消息已经发送成功 发送方开始执行本地事务逻辑
  4. 发送方根据本地事务执行结果向 MQ Server 提交二次确认(commit 或是rollback)
  5. 最终步骤:MQ Server 如果收到的是 commit 操作,则将半消息标记为可投递,MQ订阅方最终将收到该消息;若收到的是 rollback 操作则删除 half 半消息,订阅方将不会接受该消息

异常情况:

  1. 5、MQ Server 对该消息发起消息回查
  2. 6、发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果
  3. 7、发送方根据检查得到的本地事务的最终状态再次提交二次确认。
  4. 最终步骤:MQ Server基于 commit/rollback对消息进行投递或者删除。

3、最大努力通知

是对MQ事务方案的进一步优化。它在事务主动方增加了消息校对的接口,如果事务被动方没有接收到主动方发送的消息,此时可以调用事务主动方提供的消息校对的接口主动获取。
例如微信交易的结果,就是通过最大努力通知方式通知各个商户,既有回调通知,也有交易查询接口。方案如下:
在这里插入图片描述

4、MQ事务消息的优缺点

优点:

  • 消息数据独立存储 ,降低业务系统与消息系统之间的耦合
  • 吞吐量大于使用本地消息表方案

缺点:

  • 一次消息发送需要两次网络请求(half 消息 + commit/rollback 消息) 。
  • 业务处理服务需要实现消息状态回查接口。

四、Seata

这里只做简单介绍,详细请移步官方文档。Apache的官方文档

1、Seata的架构

Seata事务管理中有三个重要的角色:

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
    在这里插入图片描述
  • TM是管理板块,用来决定,哪些是本次业务中需要用到的事务(分支)。就像订单服务,我们需要1.添加新订单,2.扣除库存,3.扣除金额。而TM就是管理这三个事务,让他们开始执行;
  • RM则是每个事务的监督者,他会想TC也就是事务协调者报告,自己事务的执行状态;
  • TC再通过RM报告过来的状态,从而告诉TM是提交事务还是回滚事务。从而达到一致性。

2、分布式事务的四种解决方案

  • XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
  • TCC模式:最终一致的分阶段事务模式,有业务侵入
  • AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
  • SAGA模式:长事务模式,有业务侵入

总结

2PC/3PC:

依赖于数据库,能够很好的提供强一致性和强事务性,但延迟比较高,比较适合传统的单体应用,在同一个方法中存在跨库操作的情况,不适合高并发和高性能要求的场景。

TCC:

适用于执行时间确定且较短,实时性要求高,对数据一致性要求高,比如互联网金融企业最核心的三个服务:交易、支付、账务。

本地消息表/MQ 事务:

适用于事务中参与方支持操作幂等,对一致性要求不高,业务上能容忍数据不一致到一个人工检查周期,事务涉及的参与方、参与环节较少,业务上有对账/校验系统兜底。

Logo

更多推荐