分布式事物详解

1. 事物相关概述

1.1 数据库事物

数据库事物通常指的是事物的4个属性:原子性、一致性、隔离性、持久性。即ACID 特性。

Atomicity(原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复到事务开始前的状态,就像这个事务从来没有执行过一样。

Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。完整性包括外键约束、应用定义的等约束不会被破坏。

Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。

Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

1.2 Spring事物

Spring本身是不具有事物的,所以Spring所指的事物是对数据库事物的管理,而且Spring管理的事物一般指单库,不支持分布式事物,是为了保证一个操作中确保所有的数据库操作的原子性,要么全部成功,要么全部失败。一般是使用TransactionMananger进行管理,可以通过Spring的注入来完成此功能。
Spring事务管理方式
Spring事务参数说明
Spring事务传播机制
Spring事务隔离级别
Spring事物失效场景
Spring事物不是本章重点,具体可参考Spring框架详解.

1.3 分布式事物

分布式事务指的是 一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,所产生的事务问题。一般在多数据源多服务的情况下的事物,无法保证四大事物特性ACID,如果涉及到多数据源多服务的情况要保证事物的原子一致隔离持久四大特性往往需要借助三方工具组件实现。

2. 分布式事务解决方案

2.1 2阶段提交(2PC)

二阶段提交协议(Two-phase Commit,即 2PC)是常用的分布式事务解决方案,即将事务的提交过程分为两个阶段来进行处理。
两个阶段:一阶段(投票阶段),两阶段(提交阶段)
参与角色:事务协调者(事务管理器),事务参与者(资源管理器)

一阶段(投票阶段)
在这里插入图片描述1.协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待答复
2.各参与者执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)
3.如参与者执行成功,给协调者反馈同意,否则反馈中止

二阶段(提交阶段)
二阶段提交
当协调者发送投票请求所有参与者都回复同意时执行两阶段提交操作。
在这里插入图片描述1.协调者节点向所有参与者节点发出正式提交(commit)的请求。
2.参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
3.参与者节点向协调者节点发送ack完成消息。
4.协调者节点收到所有参与者节点反馈的ack完成消息后,完成事务。

二阶段回滚
当协调者发送投票未收到响应或者提交阶段未收到响应则向所有参与者发送回滚请求。
在这里插入图片描述1.协调者节点向所有参与者节点发出回滚操作(rollback)的请求。
2.参与者节点利用阶段1写入的undo信息执行回滚,并释放在整个事务期间内占用的资源。
3.参与者节点向协调者节点发送ack回滚完成消息。
4.协调者节点受到所有参与者节点反馈的ack回滚完成消息后,取消事务。

2PC的缺点
二阶段提交看起来确实能够提供原子性的操作,但是不幸的是,二阶段提交还是有几个缺点的:
1.性能问题:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
2.可靠性问题:参与者发生故障。协调者需要给每个参与者额外指定超时机制,超时后整个事务失败。协调者发生故障。参与者会一直阻塞下去。需要额外的备机进行容错。
3.数据一致性问题:二阶段无法解决的问题:协调者在发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
4.实现复杂:牺牲了可用性,对性能影响较大,不适合高并发高性能场景。

2PC的优点
尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。(其实也不能100%保证强一致)

2.2 3阶段提交(3PC)

三阶段提交协议,是二阶段提交协议的改进版本,三阶段提交有两个改动点。
1.在协调者和参与者中都引入超时机制。
2.在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。处理流程如下:
在这里插入图片描述阶段一:CanCommit阶段
3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

事务询问:协调者向所有参与者发出包含事务内容的 canCommit 请求,询问是否可以提交事务,并等待所有参与者答复。
响应反馈:参与者收到 canCommit 请求后,如果认为可以执行事务操作,则反馈 yes 并进入预备状态,否则反馈 no。

阶段二:PreCommit阶段
协调者根据参与者的反应情况来决定是否可以进行事务的PreCommit操作。根据响应情况,有以下两种可能。

假如所有参与者均反馈 yes,协调者预执行事务。
发送预提交请求 :协调者向参与者发送PreCommit请求,并进入准备阶段
事务预提交 :参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中(但不提交事务)
响应反馈 :如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
发送中断请求 :协调者向所有参与者发送abort请求。
中断事务 :参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

阶段三:doCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况。进入阶段 3 后,无论协调者出现问题,或者协调者与参与者网络出现问题,都会导致参与者无法接收到协调者发出的 do Commit 请求或 abort 请求。此时,参与者都会在等待超时之后,继续执行事务提交。

执行提交
发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
响应反馈 事务提交完之后,向协调者发送ack响应。
完成事务 协调者接收到所有参与者的ack响应之后,完成事务。

中断事务:任何一个参与者反馈 no,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务。
发送中断请求 如果协调者处于工作状态,向所有参与者发出 abort 请求
事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
反馈结果 参与者完成事务回滚之后,向协调者反馈ACK消息
中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。

3PC优点
相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。避免了协调者单点问题,阶段 3 中协调者出现问题时,参与者会继续提交事务。

3PC缺点
数据不一致问题依然存在,当在参与者收到 preCommit 请求后等待 doCommit 指令时,此时如果协调者请求中断事务,而协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。

2.3 TCC(事务补偿)

TCC(Try Confirm Cancel)方案是一种应用层面侵入业务的两阶段提交。是目前最火的一种柔性事务方案,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。

TCC分为两个阶段,分别如下:
第一阶段:Try(尝试),主要是对业务系统做检测及资源预留 (加锁,锁住资源)
第二阶段:本阶段根据第一阶段的结果,决定是执行confirm还是cancel
Confirm(确认):执行真正的业务(执行业务,释放锁)
Cancle(取消):是预留资源的取消(出问题,释放锁)
在这里插入图片描述为了方便理解,下面以电商下单为例进行方案解析,这里把整个过程简单分为扣减库存,订单创建 2 个步骤,库存服务和订单服务分别在不同的服务器节点上。

①Try 阶段
TCC 机制中的 Try 仅是一个初步操作,它和后续的确认一起才能真正构成一个完整的业务逻辑,这个阶段主要完成:

完成所有业务检查( 一致性 ) 。
预留必须业务资源( 准隔离性 ) 。
Try 尝试执行业务。

②Confirm / Cancel 阶段
根据 Try 阶段服务是否全部正常执行,继续执行确认操作(Confirm)或取消操作(Cancel)。

Confirm 和 Cancel 操作满足幂等性,如果 Confirm 或 Cancel 操作执行失败,将会不断重试直到执行完成。
Confirm:当 Try 阶段服务全部正常执行, 执行确认业务逻辑操作。

这里使用的资源一定是 Try 阶段预留的业务资源。在 TCC 事务机制中认为,如果在 Try 阶段能正常的预留资源,那 Confirm 一定能完整正确的提交。
Confirm 阶段也可以看成是对 Try 阶段的一个补充,Try+Confirm 一起组成了一个完整的业务逻辑。
Cancel阶段当 Try 阶段存在服务执行失败, 进入 Cancel 阶段。Cancel 取消执行,释放 Try 阶段预留的业务资源,上面的例子中,Cancel 操作会把冻结的库存释放,并更新订单状态为取消。

2.4 最终一致性

TCC 事务机制以初步操作(Try)为中心的,确认操作(Confirm)和取消操作(Cancel)都是围绕初步操作(Try)而展开。因此,Try 阶段中的操作,其保障性是最好的,即使失败,仍然有取消操作(Cancel)可以将其执行结果撤销。

Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。也就是说只要Try成功,Confirm一定成功(TCC设计之初的定义) 。Confirm与Cancel如果失败,由TCC框架进行重试补偿,存在极低概率在CC环节彻底失败,则需要定时任务或人工介入。

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

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

2.5 本地消息表

本地消息表的方案最初是由 eBay 提出,核心思路是将分布式事务拆分成本地事务进行处理。
通过在事务主动发起方额外新建事务消息表,事务发起方处理业务和记录事务消息在本地事务中完成,轮询事务消息表的数据发送事务消息,事务被动方基于消息中间件消费事务消息表中的事务。

这样可以避免以下两种情况导致的数据不一致性:

业务处理成功、事务消息发送失败
业务处理失败、事务消息发送成功

在这里插入图片描述

2.6 事务消息

事务消息也称MQ事务方案(可靠消息事务),是基于 MQ 的分布式事务方案其实是对本地消息表的封装,将本地消息表基于 MQ 内部,其他方面的协议基本与本地消息表一致。
MQ事务方案整体流程和本地消息表的流程很相似,如下图:
在这里插入图片描述

2.7 最大努力通知

最大努力通知也称为定期校对,是对MQ事务方案的进一步优化。它在事务主动方增加了消息校对的接口,如果事务被动方没有接收到消息,此时可以调用事务主动方提供的消息校对的接口主动获取。

最大努力通知的整体流程如下图:
在这里插入图片描述

2.8 Saga事务

Saga 事务源于 1987 年普林斯顿大学的 Hecto 和 Kenneth 发表的如何处理 long lived transaction(长活事务)论文。
Saga 事务核心思想是将长事务拆分为多个本地短事务,由 Saga 事务协调器协调,如果正常结束那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作。

Saga 事务基本协议如下:

每个 Saga 事务由一系列幂等的有序子事务(sub-transaction) Ti 组成。
每个 Ti 都有对应的幂等补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果。

TCC事务补偿机制有一个预留(Try)动作,相当于先报存一个草稿,然后才提交;Saga事务没有预留动作,直接提交。
对于事务异常,Saga提供了两种恢复策略,分别如下:向后恢复(backward recovery),向前恢复(forward recovery)。

向后恢复(backward recovery)
在执行事务失败时,补偿所有已完成的事务,是“一退到底”的方式。如下图:
在这里插入图片描述
从上图可知事务执行到了支付事务T3,但是失败了,因此事务回滚需要从C3,C2,C1依次进行回滚补偿。
对应的执行顺序为:T1,T2,T3,C3,C2,C1
这种做法的效果是撤销掉之前所有成功的子事务,使得整个 Saga 的执行结果撤销。

向前恢复(forward recovery)
也称之为:勇往直前,对于执行不通过的事务,会尝试重试事务,这里有一个假设就是每个子事务最终都会成功。
流程如下图:

在这里插入图片描述
适用于必须要成功的场景,事务失败了重试,不需要补偿。

Saga事务有两种不同的实现方式,分别如下:

命令协调(Order Orchestrator)
事件编排(Event Choreographyo)

命令协调
中央协调器(Orchestrator,简称 OSO)以命令/回复的方式与每项服务进行通信,全权负责告诉每个参与者该做什么以及什么时候该做什么。整体流程如下图:
在这里插入图片描述

3. 分布式事物总结

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

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

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

4.Saga 事务:由于 Saga 事务不能保证隔离性,需要在业务层控制并发,适合于业务场景事务并发操作同一资源较少的情况。Saga 相比缺少预提交动作,导致补偿动作的实现比较麻烦,例如业务是发送短信,补偿动作则得再发送一次短信说明撤销,用户体验比较差。Saga 事务较适用于补偿动作容易处理的场景。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值