前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分布式事务

分布式事务

原创
作者头像
羽毛球初学者
发布2024-10-16 18:03:04
620
发布2024-10-16 18:03:04
举报
文章被收录于专栏:JAVA基础知识

在分布式系统中,多个服务配合完成一个流程,不同服务执行结果不一定都成功,这时候就会产生问题。比如订单微服务和库存微服务,下单的同时订单微服务请求库存微服务减库存, 如果订单服务执行成功,但是库存服务执行失败没有扣减库存,那么就会出现超卖现象。

针对此问题,引入分布式事务进行控制。在深入了解分布式事务前,需要先了解一些理论。

CAP 理论

CAP 定理又被称作布鲁尔定理,是加州大学伯克利分校的计算机科学家埃里克·布鲁尔(Eric Brewer)在 2000 年的 ACM PODC 上提出的一个猜想。2002 年,麻省理工学院的赛斯·吉尔伯特(Seth Gilbert)和南希·林奇(Nancy Lynch)发表了布鲁尔猜想的证明,使之成为分布式计算领域公认的一个定理。简单来说:在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。

  • 一致性(Consistency):对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
  • 可用性(Availability):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。
  • 分区容错性(Partition Tolerance):当出现网络分区后,系统能够继续“履行职责”。

虽然 CAP 理论定义是三个要素中只能取两个,但放到分布式环境下来思考,我们会发现必须选择 P(分区容忍)要素,因为网络本身无法做到 100% 可靠,有可能出故障,所以分区是一个必然的现象。如果我们选择了 CA 而放弃了 P,那么当发生分区现象时,为了保证 C,系统需要禁止写入,当有写入请求时,系统返回 error(例如,当前系统不允许写入),这又和 A 冲突了,因为 A 要求返回 no error 和 no timeout。因此,分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。

CP架构

假设2个节点 N1 和 N2,当发生分区现象后,N1 节点上的数据已经更新到 y,但由于 N1 和 N2 之间的复制通道中断,数据 y 无法同步到 N2,N2 节点上的数据还是 x。这时客户端 C 访问 N2 时,N2 需要返回 Error,提示客户端 C“系统现在发生了错误”,这种处理方式违背了可用性(Availability)的要求,因此 CAP 三者只能满足 CP。

AP 架构

还是 N1、N2 两个节点,为了保证可用性,当发生分区现象后,N1 节点上的数据已经更新到 y,但由于 N1 和 N2 之间的复制通道中断,数据 y 无法同步到 N2,N2 节点上的数据还是 x。这时客户端 C 访问 N2 时,N2 将当前自己拥有的数据 x 返回给客户端 C 了,而实际上当前最新的数据已经是 y 了,这就不满足一致性(Consistency)的要求了,因此 CAP 三者只能满足 AP。注意:这里 N2 节点返回 x,虽然不是一个“正确”的结果,但是一个“合理”的结果,因为 x 是旧的数据,并不是一个错乱的值,只是不是最新的数据而已。

BASE 理论

BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency),核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。满足 BASE 理论的事务,我们称之为“柔性事务”。

  • 基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。比如电商网站交易付款出现问题了,商品依然可以正常浏览。
  • 软状态:由于不要求强一致性,所以 BASE 允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用性,如订单的"支付中"、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。
  • 最终一致:最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟等待。

有了这些理论基础,就可以往下探讨分布式事务解决方案了。

XA 方案

在了解XA方案前,首先了解什么是XA。XA 是由 X/Open组织(即现在的 Open Group )定义的分布式事务处理模型,它包括:

  • 应用程序( AP )
  • 事务管理器( TM ):交易中间件等
  • 资源管理器( RM ):关系型数据库等
  • 通信资源管理器( CRM ):消息中间件等

XA 规范定义了交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。而XA接口函数由数据库厂商提供。 具体使用步骤如下:

  • 配置 TM,给 TM 注册 RM 作为数据源。其中,一个 TM 可以注册多个 RM。
  • AP 向 TM 发起一个全局事务。这时,TM 会发送一个 XID(全局事务ID)通知各个 RM。
  • AP 从 TM 获取资源管理器的代理(例如:使用JTA接口,从TM管理的上下文中,获取出这个TM所管理的RM的JDBC连接或JMS连接),间接操作 RM 进行业务操作。TM 在每次 AP 操作时把 XID 传递给 RM,RM 正是通过这个 XID 来完成和事务有关系的操作。
  • AP 结束全局事务时,TM 会通知 RM ,然后 RM 开始二段提交,也就是prepare - commit的过程。
  • TM 根据 RM 的二段提交执行结果,向 AP 返回事务执行状态。

基于XA规范实现的分布式解决方案主要有有 2PC 和 3PC。

2PC(二阶段提交)

二阶段提交协议的算法思路可以概括为:每个参与者(RM)将操作成败通知协调者(TM),再由协调者根据所有参与者的反馈情报,决定各参与者是否要提交操作还是中止操作。它的具体工作内容是:

  • ‌准备阶段:TM 向所有 RM 发送准备请求,RM 准备执行事务并锁住所需资源。如果所有 RM 都准备就绪,则进入提交阶段;否则,回滚所有操作。
  • ‌提交阶段:如果所有 RM 都准备就绪,TM 向所有 RM 发送提交请求,完成事务。如果任何 RM 遇到问题,则回滚所有操作。

2PC 提高了数据一致性的概率,实现成本较低。但是缺点也比较明显:

  • 单点问题:事务协调者宕机,参与者会一直阻塞下去;
  • 同步阻塞:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈;
  • 数据不一致:在第二阶段提交时,依然存在因网络抖动导致无法获取commit结果的情况,有可能导致数据不一致。

阿里自研的 Seata 中间件就是基于 2PC 实现的。在 Seata 中,分布式事务的执行流程:

  1. TM 开启分布式事务(TM 向 TC 注册全局事务记录);
  2. 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 );
  3. TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务);
  4. TC 汇总事务信息,决定分布式事务是提交还是回滚;
  5. TC 通知所有 RM 提交/回滚 资源,事务二阶段结束。

3PC(三阶段提交)

三阶段提交协议是二阶段提交协议的改进版本,它相较于 2PC 来说,增加了 CanCommit阶段 并引入了超时机制。具体工作流程是:

  • CanCommit阶段:所有参与者确认自己是否能正常进行事务(是否能访问到对应的资源),把结果发送给协调者,以及是否能接到协调者的消息。
  • PreCommit阶段:所有参与者执行事务,但是不提交事务,仅仅是把事务执行成功或失败的消息发送给协调者。
  • DoCommit阶段:协调者向所有参与者发起事务提交或回滚的通知。

通过加入 CanCommit阶段进行尝试,避免了像 2PC那样在第一阶段就尝试执行事务并生成undo log。此外在 3PC 中的 DoCommit 阶段,如果事务参与者迟迟没有收到协调者的 commit 通知,就会自动进行本地commit,相对有效地解决了协调者单点故障的问题。(因为参与者能进入第三阶段,说明参与者在第二阶段已经收到了协调者的PreCommit消息,而协调者发送PreCommit消息的前提是,在第二阶段开始之前,协调者收到了所有参与者的CanCommit响应都是Yes。这说明所有的参与者都认为自己有能力正确处理处理事务。所以,当参与者进入第三阶段后,由于网络超时等原因,参与者会在等待超时后自动提交,因为参与者相信,直接提交的话,有很大几率是整个分布式事务是成功的。)

TCC方案

实现原理

TCC方案是采用最终一致性的方式实现的服务层柔性分布式事务方案,采用Try、Confirm、Cancel三个阶段来处理分布式事务,每个阶段具体负责的工作为:

  • Try:完成业务检查及资源预留。
  • Confirm:完成做业务确认操作。
  • Cancel:实现一个与Try相反的操作即回滚操作。

如果在 Confirm 和 Cancel 阶段失败,TCC 会不停重试调用Confirm 或者 Cancel 方法,直到成功为止。

三大问题

使用 TCC 方案时,有三个典型问题:空回滚、幂等和悬挂。

空回滚

当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败,这个时候其实是没有执行 Try 阶段,当故障恢复后,分布式事务进行回滚则会调用二阶段的 Cancel 方法,从而形成空回滚。

解决思路很简单,就是需要知道一阶段是否执行,如果执行了,那就是正常回滚,否则就执行空回滚。前面已经说过 TM 在发起全局事务时生成全局事务记录,全局事务ID 是贯穿整个分布式事务调用链条的,只需要再额外增加一张分支事务记录表,其中有全局事务 ID 和分支事务 ID,第一阶段 Try 方法里会插入一条记录,表示一阶段执行了。在Cancel 里读取该记录,如果该记录存在,则正常回滚;如果该记录不存在,则是空回滚。

幂等

为了保证TCC二阶段提交重试机制不会引发数据不一致,要求 TCC 的二阶段 Try、Confirm 和 Cancel 接口保证幂等,这样不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致数据不一致等严重问题。

解决思路在分支事务记录中增加执行状态,每次执行前都查询该状态。

悬挂

悬挂就是对于一个分布式事务,其二阶段 Cancel 接口比 Try 接口先执行。出现原因是在 RPC 调用分支事务 Try 时,先注册分支事务,再执行RPC调用,如果此时 RPC 调用的网络发生拥堵,通常 RPC 调用是有超时时间的,RPC 超时以后,TM就会通知RM回滚该分布式事务,可能回滚完成后,RPC 请求才到达参与者真正执行,而一个 Try 方法预留的业务资源,只有该分布式事务才能使用,该分布式事务第一阶段预留的业务资源就再也没有人能够处理了,对于这种情况,我们就称为悬挂,业务资源预留后没法继续处理。

解决思路是如果二阶段执行完成,那一阶段就不能再继续执行。在执行一阶段事务时判断在该全局事务下,“分支事务记录”表中是否已经有二阶段事务记录,如果有则不执行Try。

与XA方案的区别

  • XA 协议采用刚性事务方案,性能和吞吐率较低,TCC采用柔性分布式事务方案,性能更优越。
  • TCC 方案对业务的侵入性较大,需要编写大量业务代码的try、confirm、cancel方法,还需要考虑方法幂等性问题。

可靠消息最终一致性方案

可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。

这种方案需要考虑以下问题:

  • 本地事务与消息发送的原子性问题,可细分为两种情况:
    • 先发送消息,再操作数据库:这种情况下无法保证数据库操作与发送消息的一致性,因为可能发送消息成功,数据库操作失败。
    • 先进行数据库操作,再发送消息:这种情况下貌似没有问题,如果发送MQ消息失败,就会抛出异常,导致数据库事务回滚。但如果是超时异常,数据库回滚,但MQ其实已经正常发送了,同样会导致不一致。
  • 事务参与方接收消息的可靠性:事务参与方必须能够从消息队列接收到消息,如果接收消息失败可以重复接收消息。
  • 消息重复消费的问题。

本地消息表解决方案

此方案的核心是通过本地事务保证数据业务操作和消息的一致性,然后通过定时任务将消息发送至消息中间件,待确认消息发送给消费方成功再将消息删除。这种方案能够保障消息可靠、最终一致。

最大努力通知方案

顾名思义,发起通知方通过一定的机制最大努力将业务处理结果通知到接收方。具体包括:

  • 有一定的消息重复通知机制。因为接收通知方可能没有接收到通知,此时要有一定的机制对消息重复通知。
  • 消息校对机制。如果尽最大努力也没有通知到接收方,或者接收方消费消息后要再次消费,此时可由接收方主动向通知方查询消息信息来满足需求。

以上就是分布式事务的主流解决方案。分布式事务问题无可避免,只能根据具体业务场景去选择设计合理的方式。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CAP 理论
    • CP架构
      • AP 架构
      • BASE 理论
      • XA 方案
        • 2PC(二阶段提交)
          • 3PC(三阶段提交)
          • TCC方案
            • 实现原理
              • 三大问题
                • 空回滚
                • 幂等
                • 悬挂
              • 与XA方案的区别
              • 可靠消息最终一致性方案
                • 本地消息表解决方案
                • 最大努力通知方案
                相关产品与服务
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档