写点什么

分布式系统学习 10:分布式事务

作者:卷福同学
  • 2025-01-26
    湖北
  • 本文字数:3279 字

    阅读完需:约 11 分钟

这是小卷对分布式系统架构学习的第 13 篇文章,今天学习面试中高频问题:分布式事务,为什么要用分布式事务,分布式事务的实现方案有哪些,方案对比优缺点;

1.知识体系

1.为什么要用分布式事务

单体架构时,以本地事务为例,业务场景是下单场景,用户下单、创建订单、扣减库存这些操作都可以在一个数据库事务中完成。



而随着业务的增长,系统转变为分布式系统,原有的单体架构也拆分为多个微服务。下单场景需要在多个服务间操作,需要保证所有操作都能成功,保证整个下单流程的数据一致性,就需要用到分布式事务了


2.理论

  • 分布式理论的 CP -> 刚性事务


遵循 ACID,对数据要求强一致性


  • 分布式理论的 AP+BASE -> 柔性事务


遵循 BASE,允许一定时间内不同节点的数据不一致,但要求最终一致。


这里重新复习一遍 BASE 理论是什么:


  • 基本可用 Basically Available

  • 软状态 Soft State

  • 最终一致性 Eventually Consistent


基本可用:是指系统出现未知故障时,还是能用的;


软状态:允许系统存在中间态,即所有副本数据允许存在延迟;


最终一致性:存在软状态,在一定时间后,所有副本数据保持一致,从而达到数据最终一致性;

3.刚性事务(CP 模式)

刚性事务指的是强一致性,基础是 XA 协议,XA 协议是一个基于数据库的分布式事务协议,其分为两部分:事务管理器(Transaction Manager)**和**本地资源管理器(Resource Manager)。事务管理器作为一个全局的调度者,负责对各个本地资源管理器统一号令提交或者回滚;


而 2PC (两阶段提交)和 3PC(三阶段提交)都是由 XA 协议衍生出来的

3.1 两阶段提交(2PC)

引入一个作为协调者(coordinator)的组件来统一掌控所有参与者(participant)的操作结果,并最终指示这些节点是否要把操作结果进行真正的提交


2PC 指的是 Prepare & Commit


第一阶段:准备阶段


  • 协调者向所有参与者发送 REQUEST-TO-PREPARE

  • 当参与者收到 REQUEST-TO-PREPARE 消息后,它向协调者发送消息 PREPARE 或者 NO,表示事务是否准备好;如果发送是 NO,那么事务回滚;


第二阶段:提交阶段


  • 协调者收集所有参与者的返回信息,如果所有参与者都回复 PREPARED,那么协调者向所有参与者发送 COMMIT 消息,否则,协调者发送 ABORT 消息

  • 参与者收到协调者发来的 Commit 消息或 Abort 消息,它将执行提交或回滚,并向协调者发送 DONE 消息确认



两阶段提交的缺点:


  • 网络抖动导致数据不一致:第二阶段协调者向参与者发送 commit 命令后,如果发生网络抖动,有一部分参与者未收到 commit 请求,则无法执行事务提交,影响整个系统数据一致性;

  • 超时导致的同步阻塞问题:2PC 中所有参与者节点都是事务阻塞型,当一个节点通信超时,其余参与者都会被阻塞;

  • 单点故障的风险:整个过程严重依赖协调者,如果协调者故障,参与者处于锁定资源的状态,无法完成事务 commit 的操作。即使重新选择一个协调者,也无法解决因前一个协调者宕机导致的阻塞问题;


2PC 只适用于两个数据库(数据库实现了 XA 协议)之间使用,限制较大,两个系统间无法使用

3.2 三阶段提交(3PC)

在 2PC 的基础上,第一阶段和第二阶段中插入一个准备阶段,同时在协调者和参与者中都引入超时机制,当参与者为收到协调者发送的 commit 请求后,也会对本地事务 commit,不会一直阻塞等待


过程如下:


  • CanCommit:协调者向所有参与者发生 Cancommit 命令,算法可以执行事务提交操作,如果都响应 YES,则下一阶段;

  • PreCommit:协调者向所有参与者发送 Precommit 命令,是否可以进行事务预提交操作。参与者如果已执行了事务操作,则回复 YES,进入下一阶段。如果回复 NO,或者协调者没有收到参与者的回复,协调者就向所有参与者发送 Abort 请求,执行事务的中断;

  • DoCommit:所有参与者已经回复 YES,协调者发 DoCommit 命令正式提交事务,如果协调者没有收到参与者的 ACK 响应,则发 Abort 请求给所有参与者,中断事务。



小结:


2PC 存在使用限制的问题,3PC 存在数据不一致的问题,两者在实际中很少使用;

4.柔性事务(AP +BASE 最终一致性)

柔性事务要求最终一致性,允许有中间态,柔性事务可以分为:TCC、Saga、本地消息表、MQ 事务方案、最大努力通知

4.1 TCC 补偿事务

TCC(Try Confirm Cancel)补偿事务,与 2PC 不同的是,2PC 是在 DB 层面,TCC 是在应用层面


三个操作步骤:


  • Try 阶段:完成业务检查,预留必须得业务资源;

  • Confirm 阶段:执行业务逻辑,只使用 Try 阶段预留的业务资源。Confirm 需满足幂等性,保证一个分布式事务只成功一次;

  • Cancel 阶段:取消操作,释放 Try 阶段预留的业务资源,需要幂等性;


4.2 Saga 事务

Saga 可以看做一个异步的、利用队列实现的补偿事务。

由一系列本地事务构成,每个本地事务更新了数据库后,会发布一条消息来触发 Saga 中的下一个本地事务的执行,如果某个本地事务失败了,Saga 会执行这个失败事务之前 已提交的所有事务的补偿操作


Saga 的实现最流行的两种方式是:


  • 基于事件的方式。这种方式没有协调中心,整个模式的工作方式就像舞蹈一样,各个舞蹈演员按照预先编排的动作和走位各自表演,最终形成一只舞蹈。处于当前 Saga 下的各个服务,会产生某类事件,或者监听其它服务产生的事件并决定是否需要针对监听到的事件做出响应

  • 基于命令的方式。这种方式的工作形式就像一只乐队,由一个指挥家(协调中心)来协调大家的工作。协调中心来告诉 Saga 的参与方应该执行哪一个本地事务


基于事件的方式


事务回滚:


  • 基于事件的回滚,需要相关服务提供补偿操作接口,某个节点发生无法执行事件操作时,需要发送事件通知,其他已执行了事务的节点监听事件并回应

  • 优点:简单容易理解,适用于分布式事务只有 2-4 个步骤的场景。示例如:下单-扣款-库存减货-物流服务-订单完成 这样简单的场景

  • 缺点:参与业务方多时,会出现很多问题

4.3 本地消息表

本地消息表的核心是将分布式事务拆成本地事务进行处理,最初是由 eBay 提出的


下面以一个订单场景具体说明本地消息表的实现


例如,可以在订单库新增一个消息表,将新增订单和新增消息放到一个事务里完成,然后通过轮询的方式去查询消息表,将消息推送到 MQ,库存服务去消费 MQ。



执行流程为:


  1. 订单服务,在一个事务里增加一个订单和一条消息,并提交

  2. 订单服务通过轮询的方式,查出未同步的消息,发到 MQ,从设置失败重试机制;

  3. 库存服务,负责接收 MQ 消息,进行消费修改库存,由消费方保证幂等性;

  4. 库存服务修改成功后,调 RPC 接口修改订单服务的消息表状态;

  5. 修改失败,等待重试


优点:方案轻量,消息可靠性不依赖消息中间件;


缺点:与业务强耦合,不可公用,消息数据与业务库同库,占资源;

4.4 MQ 消息事务

MQ 事务是对本地消息表的封装,将本地消息表存到 MQ 内部了,而不是业务数据库

将两个事务通过消息队列进行异步解耦,加上重试机制保证最终一致性



发消息逻辑如下:



  • 发送方向 MQ server 端发送 half 消息;

  • MQ server 将消息持久化后,发 ACK 给发送方

  • 发送方开始执行本地事务

  • 执行完成后,向 MQ server 提交二次确认

  • MQ server 收到 commit 状态将半消息标记为可投递,订阅方将收到消息;MQ server 如收到 rollback 状态则删除半消息,订阅方收不到消息;


缺点:一次消息发送需要两次网络请求(half + commit/rolllback 消息)

4.5 最大努力通知

也成为定期校对,是对 MQ 事务的进一步优化。

事务发起方增加了消息校对接口,也就是查询接口,事务接收方可以自行调用接口主动获取操作结果


逻辑如下:


事务主动方尽最大努力(重试,轮询....)将事务发送给事务接收方,但是仍然存在消息接收不到,此时需要事务被动方主动调用事务主动方的消息校对接口查询业务消息并消费,这种通知的可靠性是由事务被动方保证的



适用场景:


业务通知类型的场景,如微信交易的结果,就是通过最大努力通知方式通知各个商户,既有回调通知,也有交易查询接口

5. Seata 框架

开源的分布式事务解决方案,提供了 AT、TCC、SAGA、XA 事务模式,不需要自己手动实现分布式事务,直接使用框架就行


有以下几个角色:


  • TC (Transaction Coordinator) - 事务协调者: 维护全局和分支事务的状态,驱动全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器: 定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器: 管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。



发布于: 刚刚阅读数: 5
用户头像

卷福同学

关注

一个在福报厂修福报的程序员 2020-04-30 加入

阿里巴巴Java资深开发,终身学习者,持续文章撰写者,福报厂卷着。目前主要从事地图领域相关业务,负责100万QPS的系统,有丰富的高并发高可用经验

评论

发布
暂无评论
分布式系统学习10:分布式事务_分布式事务_卷福同学_InfoQ写作社区