分布式事务基础

前言

术语

  • TX 协议:应用或者应用服务器与事务管理器的接口
  • XA 协议:全局事务管理器与资源管理器的接口。XA 是由 X/Open组织提出的分布式事务规范,该规范主要定义了全局事务管理器和局部资源管理器之间的接口,主流的数据库产品都实现了 XA 接口。XA接口是一个双向的系统接口,在事务管理器以及多个资源管理器之间作为通信桥梁。之所以需要 XA是因为在分布式系统中从理论上讲两台机器是无法达到一致性状态的,因此引入一个单点进行协调。由全局事务管理器管理和协调的事务可以跨越多个资源和进程。全局事务管理器一般使用XA 二阶段协议与数据库进行交互。

分布式理论

CAP 理论:

CAP 定理是由加州大学伯克利分校 Eric Brewer 教授提出来的,他指出 WEB 服务无法同时满足一下三个属性:

  • 一致性 (Consistency):客户端知道一系列的操作都会同时发生 (生效)
  • 可用性 (Availability):每个操作都必须以可预期的响应结束
  • 分区容错性 (Partition tolerance):即使出现单个组件无法可用,操作依然可以完成
    具体地讲在分布式系统中,任何数据库设计或者 Web应用至多只能同时支持上面的两个属性。显然,任何横向扩展策略都要依赖于数据分区。因此,设计人员必须在一致性与可用性之间做出选择。

BASE 理论:

在分布式系统中,往往追求的是可用性,它的重要程序比一致性要高,那么如何实现高可用性呢?前人已经给我们提出来了另外一个理论,就是 BASE 理论,它是用来对 CAP 定理进行进一步扩充的。BASE 理论指的是:

  • Basically Available(基本可用)
  • Soft state(软状态)
  • Eventually consistent(最终一致性)

BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

酸碱平衡:

ACID 能够保证事务的强一致性,即数据是实时一致的,这在本地事务中是没有问题的。在分布式事务中,强一致性会极大影响分布式系统的性能,因此分布式系统中遵循 BASE 理论即可。但分布式系统的不同业务场景对一致性的要求也不同。如交易场景下,就要求强一致性,此时就需要遵循 ACID 理论,而在注册成功后发送短信验证码等场景下,并不需要实时一致,因此遵循 BASE 理论即可。因此要根据具体业务场景,在 ACID 和 BASE 之间寻求平衡。

分布式事务基础

事务

事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操都成功,要么所有的操作都被撤销。简单地说,事务提供一种” 要么什么都不做,要么做全套 “机制。

本地事务

本地事务其实可以认为是数据库提供的事务机制。说到数据库事务就不得不说,数据库事务中的四大特性(ACID):

  • A:原子性(Atomicity),一个事务中的所有操作,要么全部完成,要么全部不完成
  • C:一致性(Consistency),在一个事务执行之前和执行之后数据库都必须处于一致性状态
  • I:隔离性(Isolation),在并发环境中,当不同的事务同时操作相同的数据时,事务之间互不影响
  • D:持久性(Durability),指的是只要事务成功结束,它对数据库所做的更新就必须永久的保存下来

数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个不可分割的执行单元,该执行单元中的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚。

分布式事务

分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。一句话概括就是,一次业务操作需要跨多个数据源或者需要跨多个系统进行远程调用,就会产生分布式事务问题。

分布式事务的场景

  • 单体系统访问多个数据库:一个服务需要调用多个数据库实例完成数据的增删改操作
    在这里插入图片描述
  • 多个微服务访问同一个数据库:多个服务需要调用一个数据库实例完成数据的增删改操作

在这里插入图片描述

  • 多个微服务访问多个数据库:多个服务需要调用一个数据库实例完成数据的增删改操作
    在这里插入图片描述

分布式事务协议

两阶段提交协议(2PC)

分布式系统的一个难点是如何保证架构下多个节点在进行事务性操作的时候保持一致性。为实现这个目的,二阶段提交算法的成立基于以下假设:

  • 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts),且节点之间可以进行网络通信
  • 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失
  • 所有节点不会永久性损坏,即使损坏后仍然可以恢复

第一阶段(投票阶段):

  • 协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应
  • 参与者节点执行询问发起为止的所有事务操作,并将 Undo 信息和 Redo信息写入日志(注意:若成功这里其实每个参与者已经执行了事务操作)
  • 各参与者节点响应协调者节点发起的询问,如果参与者节点的事务操作实际执行成功,则它返回一个” 同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个” 中止” 消息

第二阶段(提交执行阶段):

当协调者节点从所有参与者节点获得的相应消息都为” 同意” 时:

  • 协调者节点向所有参与者节点发出” 正式提交(Commit)” 的请求
  • 参与者节点正式完成操作,并释放在整个事务期间内占用的资源
  • 参与者节点向协调者节点发送” 完成” 消息
  • 协调者节点受到所有参与者节点反馈的” 完成” 消息后,完成事务

中断事务:

如果任一参与者节点在第一阶段返回的响应消息为” 中止”,或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

  • 协调者节点向所有参与者节点发出” 回滚操作(Rollback)” 的请求
  • 参与者节点利用之前写入的 Undo 信息执行回滚,并释放在整个事务期间内占用的资源
  • 参与者节点向协调者节点发送” 回滚完成” 消息
  • 协调者节点受到所有参与者节点反馈的” 回滚完成” 消息后,取消事务

特别注意:不管最后结果如何,第二阶段都会结束当前事务

二阶段提交的缺点:

  • 资源阻塞:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态
  • 参与者发生故障:协调者需要给每个参与者额外指定超时机制,超时后整个事务失败(没有多少容错机制)
  • 协调者发生故障:参与者会一直阻塞下去。需要额外的备机进行容错(这个可以依赖 Paxos 协议实现 HA)

二阶段无法解决的问题:协调者再发出 Commit 消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否已经被提交成功,这有可能导致数据不一致

三阶段提交协议(3PC)

与两阶段提交不同的是,三阶段提交有两个改动点:

  • 引入超时机制。同时在协调者和参与者中都引入超时机制
  • 在第一阶段和第二阶段中插入一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的

也就是说,除了引入超时机制之外,3PC 把 2PC 的准备阶段再次一分为二,这样三阶段提交就有 CanCommit、PreCommit、DoCommit 三个阶段.

CanCommit 阶段:

3PC 的 CanCommit 阶段其实和 2PC 的准备阶段很像。协调者向参与者发送 Commit 请求,参与者如果可以提交就返回 Yes 响应,否则返回 No 响应:

  • 事务询问:协调者向参与者发送 CanCommit 请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应
  • 响应反馈:参与者接到 CanCommit 请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回 Yes响应,并进入预备状态,否则反馈 No

PreCommit 阶段:

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

假如协调者从所有的参与者获得的反馈都是 Yes 响应,那么就会执行事务的预执行

  • 发送预提交请求:协调者向参与者发送 PreCommit 请求后,并进入 Prepared 阶段
  • 事务预提交:参与者接收到 PreCommit 请求后,会执行事务操作,并将 Undo 和 Redo 信息记录到事务日志中
  • 响应反馈:如果参与者成功的执行了事务操作,则返回 ACK 响应,同时开始等待最终指令

假如有任何一个参与者向协调者发送了 No 响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断

  • 发送中断请求:协调者向所有参与者发送 Abort 请求
  • 中断事务:参与者收到来自协调者的 Abort 请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断 DoCommit 阶段

该阶段进行真正的事务提交,也可以分为以下两种情况:

执行提交:

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

中断事务

  • 发送中断请求:协调者向所有参与者发送 Abort 请求
  • 事务回滚:参与者接收到 Abort 请求之后,利用其在阶段二记录的 Undo 信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源
  • 反馈结果:参与者完成事务回滚之后,向协调者发送 ACK 消息
  • 中断事务:协调者接收到参与者反馈的 ACK 消息之后,执行事务的中断

这里协调者如果没有接收到参与者发送的 ACK 响应(可能是接受者发送的不是 ACK 响应,也可能响应超时),那么就会执行中断事务。

分布式事务解决方案

全局事务(DTP 模型)

全局事务是基于 DTP 模型实现的,DTP 是由 X/Open 组织提出的一种分布式事务模型 ——X/Open Distributed Transaction Processing Reference Model。它规定了要实现分布式事务,需要三种角色:

  • AP: Application 应用系统 (微服务)
  • TM: Transaction Manager 事务管理器 (全局事务管理)
  • RM: Resource Manager 资源管理器 (数据库)

整个事务分成两个阶段:

  • 阶段一:表决阶段,所有参与者都将本事务执行预提交,并将能否成功的信息反馈发给协调者
  • 阶段二:执行阶段,协调者根据所有参与者的反馈,通知所有参与者,步调一致地执行提交或者回滚
    在这里插入图片描述
    在这里插入图片描述
    优点:
  • 提高了数据一致性的概率,实现成本较低

缺点:

  • 单点问题:事务协调者宕机
  • 同步阻塞:延迟了提交时间,加长了资源阻塞时间
  • 数据不一致:在提交的第二阶段,依然存在 Commit 结果未知的情况,有可能导致数据不一致

TCC(两阶段型、补偿型)

TCC 即为 Try Confirm Cancel,它属于补偿型分布式事务。TCC 实现分布式事务一共有三个步骤:

  • Try(尝试待执行的业务):这个过程并未执行业务,只是完成所有业务的一致性检查,并预留好执行所需的全部资源
  • Confirm(确认执行业务):确认执行业务操作,不做任何业务检查,只使用 Try 阶段预留的业务资源。通常情况下,采用 TCC 则认为Confirm 阶段是不会出错的。即只要 Try 成功,Confirm 就一定成功。若 Confirm阶段真的出错了,需引入重试机制或人工处理
  • Cancel(取消待执行的业务):取消 Try 阶段预留的业务资源。通常情况下,采用 TCC 则认为 Cancel 阶段也是一定成功的。若Cancel 阶段真的出错了,需引入重试机制或人工处理
    在这里插入图片描述
    在这里插入图片描述

TCC 两阶段提交与 XA 两阶段提交的区别:

  • XA 是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁
  • TCC 是业务层面的分布式事务,最终一致性,不会一直持有资源的锁

TCC 事务的优缺点:

  • 优点:把数据库层的二阶段提交上提到了应用层来实现,规避了数据库层的 2PC 性能低下的问题

  • 缺点:TCC 的 Try、Confirm 和 Cancel 操作功能需业务提供,开发成本高

基于可靠消息服务的分布式事务

基于可靠消息服务的方案是通过消息中间件保证上、下游应用数据操作的一致性。假设有 A 和 B 两个系统,分别可以处理任务 A 和任务 B。此时存在一个业务流程,需要将任务 A 和任务 B 在同一个事务中处理,此时就可以使用消息中间件来实现这种分布式事务。

在这里插入图片描述
第一步:消息由系统 A 投递到消息中间件

  • 1)在系统 A 处理任务 A 前,首先向消息中间件发送一条消息
  • 2)消息中间件收到后将该条消息持久化,但并不投递。持久化成功后,向 A 回复一个确认应答
  • 3)系统 A 收到确认应答后,则可以开始处理任务 A
  • 4)任务 A 处理完成后,向消息中间件发送 Commit 或者 Rollback 请求。该请求发送完成后,对系统 A
    而言,该事务的处理过程就结束了
  • 5)如果消息中间件收到 Commit,则向 B 系统投递消息;如果收到 Rollback,则直接丢弃消息。但是如果消息中间件收不到Commit 和 Rollback 指令,那么就要依靠” 超时询问机制”

超时询问机制

系统 A 除了实现正常的业务流程外,还需提供一个事务询问的接口,供消息中间件调用。当消息中间件收到发布消息便开始计时,如果到了超时没收到确认指令,就会主动调用系统 A 提供的事务询问接口询问该系统目前的状态。该接口会返回三种结果,中间件根据三种结果做出不同反应:

  • 提交:将该消息投递给系统 B
  • 回滚:直接将消息丢弃
  • 处理中:继续等待

第二步:消息由中间件投递到系统 B

消息中间件向下游系统投递完消息后便进入阻塞等待状态,下游系统便立即进行任务的处理,任务处理完成后便向消息中间件返回应答。

  • 如果消息中间件收到确认应答后便认为该事务处理完毕
  • 如果消息中间件在等待确认应答超时之后就会重新投递,直到下游消费者返回消费成功响应为止。一般消息中间件可以设置消息重试的次数和时间间隔,如果最终还是不能成功投递,则需要手工干预。这里之所以使用人工干预,而不是使用让A 系统回滚,主要是考虑到整个系统设计的复杂度问题

基于可靠消息服务的分布式事务,前半部分使用异步,注重性能;后半部分使用同步,注重开发成本。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值