分布式事务简介

提到事务这个概念,相信大家第一时间想到额是数据库的事务。所谓的数据库事务是指作为单个逻辑工作单元执行的多个数据库操作,要么同时成功,要么同时失败,它必须满足ACID特性,因为这里主要讲解的是分布式事务,所以有关数据库事务的内容这里不再展开。那么,什么是分布式事务呢?

分布式事务简介

分布式事务指的是允许多个独立的事务资源参与到一个全局的事务中。准确的说,分布式事务是指事务的参与者、支持事务的服务器、资源服务器及事务管理器分别位于分布式系统的不同节点上。
分布式事务问题也叫分布式数据一致性问题,简单来说就是如何在分布式场景中保证多个节点数据的一致性。分布式事务产生的核心原因在于存储资源的分布性。在实际应用中,我们应该尽可能地从设计层面去避免分布式事务的问题,因为任何一种解决方案都会增加系统的复杂度。

一致性分类

一致性可以分为三类:

  • 强一致性
    如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大。
  • 弱一致性
    这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。
  • 最终一致性
    最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型。一般情况下,高可用只确保最终一致性,不确保强一致性。

强一致性,读请求和写请求会串行化,串到一个内存队列里去,这样会大大增加系统的处理效率,吞吐量也会大大降低。

分布式事务理论模型

X/Open分布式事务模型

X/Open DTP是X/Open这个组织定义的一套分布式事务的标准。这个标准提出了使用两阶段提交(2PC)来保证分布式事务的完整性。X/Open DTP中包含三种角色:

  • AP:表示应用程序。
  • RM:表示资源管理器,比如数据库。
  • TM:表示事务管理器,一般指事务协调者,负责协调和管理事务,提供AP编程接口或管理RM。

实际上,分布式事务的角色和关系与本地事务的原理基本相同,不同点在于,如果此时RM代表数据库,那么TM需要能够管理多个数据库的事务,大致实现步骤如下:

  • 配置TM,把多个RM注册到TM,相当于TM注册RM作为数据源
  • AP从TM管理的RM中获取连接,如果RM是数据库则获取JDBC连接
  • AP向TM发起一个全局事务,生成全局事务ID(XID),XID会通知各个RM
  • AP通过第二步获得的连接直接操作RM完成数据操作。这时,AP在每次操作时会把XID传递给RM。
  • AP结束全局事务,TM会通知各个RM全局事务结束。
  • 根据各个RM的事务执行结果,执行提交或者回滚操作。

需要注意的是,TM和多个RM之间的事务控制,是基于XA协议来完成的。XA协议是X/Open提出的分布式事务处理规范,也是分布式事务处理的工业标准。

两阶段提交协议

两阶段提交协议的执行流程如下:

  • 准备阶段:事务管理器(TM)通知资源管理器(RM)准备分支事务,记录事务日志,并告知事务管理器的准备结果。
  • 提交/回滚阶段:如果所有的资源管理器在准备阶段都明确返回成功,则事务管理器向所有的资源管理器发起事务提交指令完成数据的变更。反之,如果任何一个资源管理器明确返回失败,则事务管理器会向所有资源管理器发送事务回滚指令。
    需要注意的是,这两个阶段都是由事务管理器发起的。

两阶段提交的优点
充分考虑了分布式系统的不可靠因素,并且采用非常简单的方式就把由于系统不可靠而导致事务提交失败的概率降到最小。

两阶段提交的缺点

  • 同步阻塞
    所有参与者(RM)都是事务阻塞型的,对于任何一次指令都必须要有明确的响应才能继续进行下一步,否则会处于阻塞状态,占用的资源一直被锁定。
  • 过于保守
    任何一个节点失败都会导致节点回滚。
  • 事务协调者的单点故障
    如果协调者在第二个阶段出现了故障,那么其他的参与者(RM)会一直处于锁定状态。
  • “脑裂”导致数据不一致问题
    在第二阶段中,事务协调者向所有参与者(RM)发送commit请求后,发生局部网络异常导致只有一部分参与者(RM)接收到了commit请求,这部分参与者(RM)收到请求后会执行commit操作,但是未收到commit请求的节点由于事务无法提交,导致数据出现不一致问题。

三阶段提交协议

从上述可知,由于两阶段提交协议中存在问题,因此出现了两阶段提交协议的改进版本,也就是三阶段提交协议。它利用超时机制解决了同步阻塞的问题,三阶段提交协议的具体描述如下:

  • 询问阶段
    事务协调者向参与者发送事务执行请求,询问是否可以完成指令,参与者只需要回答是或者不是即可,不需要做真正的事务操作,这个阶段会有超市中止机制。
  • 准备阶段
    事务协调者根据参与者的反馈结果决定是否继续执行,如果在询问阶段所有参与者都返回可以执行操作,则事务协调者会向所有参与者发送准备阶段请求,参与者收到请求后写redo和undo日志,执行事务操作但是不提交事务,然后返回ACK响应等待事务协调者的下一步通知。如果在询问阶段任意参与者返回不能执行操作的结果,那么事务协调者会向所有参与者发送事务中断请求。
  • 提交或回滚阶段
    根据上一步的执行结果决定此阶段的执行方式。如果每个参与者在上一阶段都返回成功,那么事务协调者会向所有参与者发起事务提交指令。反之,如果参与者中的任一参与者返回失败,那么事务协调者就会发起中止指令来回滚事务。

三阶段提交协议和两阶段提交协议相比的不同点

  • 增加了一个询问阶段,用于询问所有参与者是否可以执行事务操作并且响应,它的好处是,可以尽早发现无法执行的操作而中止后续的行为。
  • 在准备阶段之后,事务协调者和参与者都引入了超时机制,一旦超时,事务协调者和参与者会继续提交事务,并且认为处于成功状态,因为在这种情况下事务默认为成功的可能性比较大。

实际上,一旦超时,在三阶段提交协议下仍然可能出现数据不一致的情况,当然概率是比较小的。另外,最大的好处是基于超时机制来避免资源的永久锁定。

无论是两阶段提交还是三阶段提交都是XA协议解决分布式数据一致性问题的基本原理,但是这两种方案为了保证数据的强一致性,降低了可用性。实际上这里涉及到分布式事务的两个理论模型:CPA理论和BASE理论

CAP理论

CAP理论,又叫布鲁尔定理。简单来说它是指分布式系统中不可能同事满足一致性(C)、可用性(A)、分区容错性(P)这三个基本需求,最多同时满足两个。

  • C:数据在多个副本中要保持强一致,比如前面说的分布式数据一致性问题。
  • A:系统对外提供的服务必须一直处于可用状态,在任何故障下,客户端都能在合理的时间内获得服务端的非错误响应。
  • P:在分布式系统中遇到任何网络分区故障,系统仍然能够正常对外提供服务。
    不同节点分布在不同的子网络中时,在内部子网络正常的情况下,由于某些原因导致这些子节点之间出现网络不同的情况,导致整个系统环境被切分成若干独立的区域,这就是网络分区

CAP定理证明,在分布式系统中,要么满足CP,要么满足AP,不可能实现CAP或者CA。原因是网络通信并不是绝对可靠的,比如网络延迟、网络异常等。而在分布式系统中,即便出现网络故障也需要保证系统仍然能够正常对外提供服务,所以在分布式系统是P是必然存在的,也就是需要满足分区容错性。

如果是CA或者CAP这种情况,相当于网络百分之百可靠,否则当出现网络分区的情况时,为了保证数据的一致性,必须拒绝客户端的请求。但是如果拒绝了请求,就无法满足A,所以在分布式系统中不可能选择CA,因此只能有CP或者AP两种选择。

  • AP:对于AP来说,相当于放弃了强一致性,实现最终的一致,这是很多互联网公司解决分布式数据一致性问题的主要选择。
  • CP:放弃了高可用性,实现强一致性。前面提到的两阶段提交和三阶段提交都采用这种方案。可能导致的问题是用户完成一个操作会等待较长的时间。

BASE理论

BASE理论是由于CAP中一致性和可用性不可兼得而衍生出来的一种新的思想,BASE理论的核心思想是通过牺牲数据的强一致性来获得高可用性。它有三个特性:

  • 基本可用:分布式系统在出现故障时,允许损失一部分功能的可用性,保证核心功能的可用。
  • 软状态:允许系统中的数据存在中间状态,这个状态不影响系统的可用性,也就是允许系统中不同节点的数据副本之间的同步存在延时。
  • 最终一致性:中间状态的数据在经过一段时间之后,会达到一个最终的数据一致性。

BASE理论并没有要求数据的强一致,而是允许数据在一段时间内是不一致的,但是数据最终会在某个时间点实现一致。在互联网产品中,大部分都会采用BASE理论来实现数据的一致,因为产品的可用性对于用户来说更加重要。

分布式事务问题的常见解决方案

我们知道基于CAP理论对于数据的一致性问题有AP和CP两种方案,但是在电商等互联网场景下,基于CP的强一致性方案在数据库性能和系统处理能力上会存在一定的瓶颈。所以在互联网场景中更多采用柔性事务,所谓的柔性事务是遵循BASE理论来实现的事务模型,它有两个特性:基本可用柔性状态。下面我们介绍几种基于柔性事务模型的解决方案。

TCC补偿型方案

TCC是一种比较成熟的分布式数据一致性解决方案,它实际上是把一个完整的业务拆分为如下三个步骤:

  • Try:这个阶段主要是对数据的校验或者资源的预留。
  • Comfirm:确认真正执行的任务,只操作Try阶段预留的资源。
  • Cancel:取消执行,释放Try阶段预留的资源。

其实TCC是一种两阶段提交的思想,第一阶段通过Try进行准备工作,第二阶段Confirm/Cacnel表示Try阶段操作的确认或回滚。在分布式事务场景中,每个服务实现TCC之后,就作为其中的一个资源,参与到整个分布式事务中。然后主业务服务在第一阶段中分别调用所有TCC服务的Try方法。最后根据第一个阶段的执行情况来决定对第二阶段的Confirm或者Cancel。

在一些特殊情况下,导致服务并没有收到TCC事务协调器的Cancel或者Confirm请求,该怎么办呢?没关系,TCC事务框架会记录一些分布式事务的操作日志,保存分布式事务运行的各个阶段和状态。TCC事务协调器会根据操作日志来进行重试,以达到数据的最终一致性。
需要注意的是,TCC服务支持接口调用失败发起重试,所以TCC暴露的接口都需要满足幂等性。

基于可靠性消息的最终一致性方案

基于可靠性消息的最终一致性是互联网公司比较常用的分布式数据一致性解决方案,它主要利用消息中间件的可靠性机制来实现数据一致性的投递

例如,在支付场景中,用户完成订单的支付后不需要同步等待支付结果,可以继续做其他事情。但是对系统来说,大部分是在发起支付之后,等到第三方支付平台提供异步支付结果通知,在根据结果来设置该订单的支付状态。并且如果支付成功,大部分电商平台基于营销策略还会给账户一定的积分奖励。所以,当系统接收到第三方返回的支付结果时,需要更新支付服务的支付状态,以及更新账户服务的积分余额,这里就涉及到了数据一致性问题。类似以上的场景在现在的互联网系统中其实有很多,现在也有很多成熟的解决方案,以RocketMQ为例,它提供了事务消息模型,具体的执行逻辑如下:

  • 生产者发送一个事务消息到消息队列上,消息队列只记录这条消息的数据,此时消费者无法消费这条消息。
  • 生产者执行具体的业务逻辑,完成本地事务的操作。
  • 接着生产者根据本地事务的执行结果发送一条确认消息给消息队列服务器,如果本地事务执行成功,则发送一个Commit消息,表示在第一步中发送的消息可以被消费,否则,消息队列服务器会把第一步存储的消息删除。
  • 如果生产者在执行本地事务的过程中因为某些情况一直未给消息队列服务器发送确认,那么消息队列服务器会定时主动回查生产者获取本地事务的执行结果,然后根据回查结果来决定这条消息是否需要投递给消费者。
  • 消费队列服务器上存储的消息被生产者确认之后,消费者就可以消费这条消息,消息消费完成之后发送一个确认标识给消费队列服务器,表示该消息投递成功。
    在RocketMQ事务消息模型中,事务是由生产者来完成的,消费者不需要考虑,因为消息队列可靠性投递机制的存在,如果消费者没有签收该消息,那么消息队列服务器会重复投递,从而实现生产者的本地数据和消费者的本地数据在消息队列的机制下达到最终一致。
    事实上,在RocketMQ的事务消息模型中最核心的机制应该是事务回查,实际上查询模式在很多类似的场景中都可以用。在分布式系统中,由于网络通信的存在,服务之间的远程通信除成功和失败两种结果外,还存在一种未知状态,比如网络超时。服务提供者可以提供一个查询接口向外部输出操作的执行状态,服务调用方可以通过调用该接口得知之前操作的结果并进行相应的处理。

最大努力通知型

最大努力通知型和基于可靠性消息的最终一致性方案的实现是类似的,它是一种比较简单的柔性事务解决方案,也比较适用于对数据一致性要求不高的场景,最典型的使用场景是支付宝支付结果通知。
以商户的角度分析最大努力通知型的处理过程如下:

  • 商户先创建一个支付订单,然后调用支付宝发起支付请求。
  • 支付宝唤醒支付页面完成支付操作,支付宝同样会针对该商户创建一个支付交易,并且根绝用户的支付结果记录支付状态。
  • 支付完成后触发一个回调通知给商户,商户收到该通知后,根据结果修改本地支付订单的状态,并且返回一个处理状态给支付宝。
  • 针对这个订单,在理想状态下支付宝的交易状态和商户的交易状态会在通知完成后达到最终一致。但是由于网络的不确定性,支付结果通知可能会失败或丢失,导致商户端的支付订单的状态是未知的。所以最大努力通知型的作用就体现了,如果商户端在收到支付结果通知后没有返回一个“SUCCESS”状态码,那么这个支付结果回调请求会以衰减重试机制(逐步拉大通知的时间间隔)继续触发,直到达到最大通知次数。如果达到指定次数后商户还没有返回确认状态,怎么处理呢?
  • 支付宝提供了一个交易结果查询接口,可以根据这个支付订单号去支付宝查询支付状态,然后根据返回的结果来更新商户的支付订单状态,这个过程可以通过定时器触发,也可以通过人工对账来触发

所谓最大努力通知,就是在商户段如果没有返回一个消息确认时,支付宝会不断的进行重试,直到收到一个消息确认或者达到最大重试次数。

分布式事务框架Seata

Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。它提供了AT、TCC、Saga和XA事务模式,为开发者提供了一站式的分布式事务解决方案。

AT模式

AT模式是Seata主推的分布式事务解决方案,它是基于XA演进而来的一种分布式事务模式,所以同样分为三大模块:TM、RM和TC,其中TM和RM作为Seata的客户端与业务系统集成,TC作为Seata的服务器独立部署。TM是事务管理器,它负责向TC注册一个全局事务,并生成一个全局唯一的XID。
在AT模式下,每个数据库资源被当作一个RM,在业务层面通过JDBC标准的接口访问RM时,Seata会对所有请求进行拦截。每个本地事务进行提交时,RM都会向TC注册一个分支事务。
具体的执行流程如下:

  • TM向TC注册全局事务,并生成全局唯一的XID。
  • RM向TC注册分支事务,并将其纳入该XID对应的全局事务范围。
  • RM向TC汇报资源的准备状态。
  • TC汇总所有事务参与者的执行状态,决定分布式事务是全部回滚还是提交。
  • TC通知所有RM提交/回滚事务。

AT模式和XA一样,也是一个两阶段提交事务模型,不过AT多了很多优化。

AT模式的实现原理

暂略

Saga

Saga模式又称为长事务解决方案,主要描述的是在没有两阶段提交的情况下如何解决分布式事务问题。其核心思想是:把一个业务流程中的长事务拆分为多个本地短事务,业务流程中的每个参与者都提交真实的提交给该本地短事务,当其中一个参与者事务执行失败,则通过补偿机制补偿前面已经成功的参与者。
暂略

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值