第7章 分布式系统架构 【补充:分布式事务解决方案之 2PC、3PC】

本节内容整理自网络,以“小白不想上班”为基础,补充了3PC内容

14.3. 分布式事务解决方案之 2PC、3PC

前面学习了分布式事务的基础理论,以理论为基础,针对不同的分布式场景业界常见的解决方案有 2PC、3PC、TCC、可靠消息最终一致性、最大努力通知这几种。

14.3.1 什么是 2PC

2PC 即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase),2 是指两个阶段,P 是指准备阶段,C 是指提交阶段。

举例:张三和李四好久不见,老友约起聚餐,饭店老板要求先买单,才能出票。这时张三和李四分别抱怨近况不如意,囊中羞涩,都不愿意请客,这时只能AA。只有张三和李四都付款,老板才能出票安排就餐。但由于张三和李四都是铁公鸡,形成了尴尬的一幕:

准备阶段:老板要求张三付款,张三付款。老板要求李四付款,李四付款。
提交阶段:老板出票,两人拿票纷纷落座就餐。

例子中形成了一个事务,若张三或李四其中一人拒绝付款,或钱不够,店老板都不会给出票,并且会把已收款退回。

整个事务过程由事务管理器和参与者组成,店老板就是事务管理器,张三、李四就是事务参与者,事务管理器负责决策整个分布式事务的提交和回滚,事务参与者负责自己本地事务的提交和回滚。

在计算机中部分关系数据库如 Oracle、MySQL 支持两阶段提交协议,如下图:

(1)准备阶段(Prepare phase)

事务管理器给每个参与者发送 Prepare 消息,每个数据库参与者在本地执行事务,并写本地的 Undo/Redo 日志,此时事务没有提交。(Undo 日志是记录修改前的数据,用于数据库回滚,Redo 日志是记录修改后的数据,用于提交事务后写入数据文件);如果参与者执行成功就返回YES(可以提交事务),失败NO(不能提交事务)

(2)提交阶段(commit phase)

如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意:必须在最后阶段释放锁资源。

此阶段分两种情况:

所有参与者均反馈YES时,即提交事务。任何一个参与者反馈NO时,即中断事务。

提交事务:(所有参与者均反馈YES)

  1、协调者向所有参与者发出正式提交事务的请求(即Commit请求)。

  2、参与者执行Commit请求,并释放整个事务期间占用的资源。

  3、各参与者向协调者反馈Ack完成的消息。

  4、协调者收到所有参与者反馈的Ack消息后,即完成事务提交。

中断事务:(任何一个参与者反馈NO)

  1、协调者向所有参与者发出回滚请求(即Rollback请求)。

  2、参与者使用阶段1中的Undo信息执行回滚操作,并释放整个事务期间占用的资源。

  3、各参与者向协调者反馈Ack完成的消息。

  4、协调者收到所有参与者反馈的Ack消息后,即完成事务中断。

下图展示了2PC的两个阶段,分成功和失败两个情况说明:

 

两阶段提交存在三个问题:

(1)同步阻塞

执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。这样就造成了系统性能下降。

(2)单点故障

由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)。

(3)数据不一致(脑裂)

如果第一阶段 prepare 成功了,但是第二阶段协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。

二阶段无法解决的问题:

协调者在发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

14.3.2 什么是3PC

二阶段提交存在着诸如同步阻塞、单点问题、脑裂等缺陷,所以,研究者们在二阶段提交的基础上做了改进,提出了三阶段提交。

三阶段提交协议在协调者和参与者中都引入超时机制,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。

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

(1)引入超时机制。同时在协调者和参与者中都引入超时机制。

(2)在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

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

三个阶段的执行
(1)CanCommit阶段

3PC的CanCommit阶段其实和2PC的准备阶段很像。

协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

(2)PreCommit阶段

Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作。

根据响应情况,有以下两种可能:

1)假如Coordinator从所有的Cohort获得的反馈都是Yes响应,那么就会进行事务的预执行:

① 发送预提交请求。Coordinator向Cohort发送PreCommit请求,并进入Prepared阶段。

② 事务预提交。Cohort接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。

③ 响应反馈。如果Cohort成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

2)假如有任何一个Cohort向Coordinator发送了No响应,或者等待超时之后,Coordinator都没有接到Cohort的响应,那么就中断事务:

① 发送中断请求。Coordinator向所有Cohort发送abort请求。

② 中断事务。Cohort收到来自Coordinator的abort请求之后(或超时之后,仍未收到Cohort的请求),执行事务的中断。

(3)DoCommit阶段

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

1)执行提交

① 发送提交请求。Coordinator接收到Cohort发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有Cohort发送doCommit请求。

② 事务提交。Cohort接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。

③ 响应反馈。事务提交完之后,向Coordinator发送ACK响应。

④ 完成事务。Coordinator接收到所有Cohort的ACK响应之后,完成事务。

2)中断事务

Coordinator没有接收到Cohort发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。

三阶段提交协议和两阶段提交协议的不同:

对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)。

在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段。

PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。

3PC的优点和缺陷:

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

缺陷:脑裂问题依然存在,即在参与者收到PreCommit请求后等待最终指令,如果此时协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。

14.3.3 解决方案

14.3.3.1 XA 方案

XA 协议是由 X/Open 组织提出的分布式事务处理规范,XA 是一个分布式事务协议,由Tuxedo 提出,所以分布式事务也称为XA 事务。主要定义了事务管理器 TM 和局部资源管理器 RM 之间的接口。XA 事务是基于两阶段提交(Two-PhaseCommit,2PC)协议实现的,可以保证数据的强一致性,许多分布式关系型数据管理系统都采用此协议来完成分布式。目前主流的数据库,比如 oracle、DB2 都是支持 XA 协议的。MySQL 从 5.0 版本开始,InnoDB 存储引擎已经支持 XA 协议。

2PC的传统方案是在数据库层面实现的,如 Oracle、MySQL 都支持 2PC 协议,为了统一标准减少行业内不必要的对接成本,需要制定标准化的处理模型及接口标准,国际开放标准组织 Open Group 定义了分布式事务处理模型DTP(Distributed Transaction Processing Reference Model)。

为了让大家更明确 XA 方案的内容,下面以新用户注册送积分为例来说明:

 

执行流程如下:

1.应用程序(AP)持有用户库和积分库两个数据源。

2.应用程序(AP)通过 TM 通知用户库 RM 新增用户,同时通知积分库RM为该用户新增积分,RM 此时并未提交事务,此时用户和积分资源锁定。

3.TM 收到执行回复,只要有一方失败则分别向其他 RM 发起回滚事务,回滚完毕,资源锁释放。

4.TM 收到执行回复,全部成功,此时向所有 RM 发起提交事务,提交完毕,资源锁释放。

DTP 模型定义如下角色:

AP(Application Program):即应用程序,可以理解为使用 DTP 分布式事务的程序。

RM(Resource Manager):即资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务

TM(Transaction Manager):事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个 RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。

DTP 模型定义TM和RM之间通讯的接口规范叫 XA,简单理解为数据库提供的 2PC 接口协议,基于数据库的 XA 协议来实现 2PC 又称为 XA 方案。

以上三个角色之间的交互方式如下:

(1)TM 向 AP 提供 应用程序编程接口,AP 通过 TM 提交及回滚事务。

(2)TM 交易中间件通过 XA 接口来通知 RM 数据库事务的开始、结束以及提交、回滚等。

总结:

整个 2PC 的事务流程涉及到三个角色 AP、RM、TM。AP 指的是使用 2PC 分布式事务的应用程序;RM 指的是资源管理器,它控制着分支事务;TM 指的是事务管理器,它控制着整个全局事务。

(1)在准备阶段 RM 执行实际的业务操作,但不提交事务,资源锁定

(2)在提交阶段 TM 会接受 RM 在准备阶段的执行回复,只要有任一个RM执行失败,TM 会通知所有 RM 执行回滚操作,否则,TM 将会通知所有 RM 提交该事务。提交阶段结束资源锁释放。

XA方案的问题:

(1)需要本地数据库支持XA协议。
(2)资源锁需要等到两个阶段结束才释放,性能较差。

14.3.3.2 Seata 方案

Seata 是由阿里中间件团队发起的开源项目 Fescar,后更名为 Seata,它是一个是开源的分布式事务框架。

传统 2PC 的问题在 Seata 中得到了解决,它通过对本地关系数据库的分支事务的协调来驱动完成全局事务,是工作在应用层的中间件。主要优点是性能较好,且不长时间占用连接资源,它以高效并且对业务 0 侵入的方式解决微服务场景下面临的分布式事务问题,它目前提供 AT 模式(即 2PC)及 TCC 模式的分布式事务解决方案。

Seata 的设计思想如下:

Seata 的设计目标其一是对业务无侵入,因此从业务无侵入的 2PC 方案着手,在传统 2PC的基础上演进,并解决 2PC 方案面临的问题。

Seata 把一个分布式事务理解成一个包含了若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚。此外,通常分支事务本身就是一个关系数据库的本地事务,下图是全局事务与分支事务的关系图:

 

与传统 2PC 的模型类似,Seata 定义了 3 个组件来协议分布式事务的处理过程:

 

Transaction Coordinator(TC):

事务协调器,它是独立的中间件,需要独立部署运行,它维护全局事务的运行状态,接收 TM 指令发起全局事务的提交与回滚,负责与 RM 通信协调各分支事务的提交或回滚。

Transaction Manager(TM):

事务管理器,TM 需要嵌入应用程序中工作,它负责开启一个全局事务,并最终向 TC 发起全局提交或全局回滚的指令。

Resource Manager(RM):

控制分支事务,负责分支注册、状态汇报,并接收事务协调器 TC 的指令,驱动分支(本地)事务的提交和回滚。

还拿新用户注册送积分举例Seata的分布式事务过程:

 

具体的执行流程如下:

(1)用户服务的 TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。

(2)用户服务的 RM 向 TC 注册分支事务,该分支事务在用户服务执行新增用户逻辑,并将其纳入 XID 对应全局事务的管辖。

(3)用户服务执行分支事务,向用户表插入一条记录。

(4)逻辑执行到远程调用积分服务时(XID 在微服务调用链路的上下文中传播)。积分服务的 RM 向 TC 注册分支事务,该分支事务执行增加积分的逻辑,并将其纳入 XID 对应全局事务的管辖。

(5)积分服务执行分支事务,向积分记录表插入一条记录,执行完毕后,返回用户服务。

(6)用户服务分支事务执行完毕。

(7)TM 向 TC 发起针对 XID 的全局提交或回滚决议。

(8)TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

Seata实现2PC与传统2PC的差别:

架构层次方面:传统 2PC 方案的 RM 实际上是在数据库层,RM 本质上就是数据库自身,通过 XA 协议实现,而 Seata 的 RM 是以 jar 包的形式作为中间件层部署在应用程序这一侧的。

两阶段提交方面:传统 2PC无论第二阶段的决议是 commit 还是 rollback ,事务性资源的锁都要保持到 Phase2 完成才释放。而 Seata 的做法是在 Phase1 就将本地事务提交,这样就可以省去 Phase2 持锁的时间,整体提高效率。

14.3.4 小结

本节讲解了传统 2PC(基于数据库 XA 协议)和 Seata 实现 2PC 的两种 2PC 方案,由于 Seata 的 0 侵入性并且解决了传统 2PC 长期锁资源的问题,推荐采用 Seata 实现 2PC。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值