分布式事务(2): 两阶段提交

1,190 阅读6分钟

这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

两阶段提交 2PC

前面已经学习了分布式事务的基础理论,以理论为基础,针对不同的分布式场景业界的解决方案有 2pc 、TCC、可靠消息最终一致性、最大努力通知这几种。这片文章主要介绍两阶段提交的具体使用方式。

一、什么是 2pc

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

1.准备阶段:事务管理器给每个参与者发布Prepare消息,每个服务参与者在本地执行事务,并写在Undo/Redo日志,此时事务没有提交。(Undo日志记录修改前数据用于回滚,Redo记录修改后数据用于提交事务后写入数据文件)

2.提交阶段:如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者进行回滚,否则发送提交消息。注意:必须在最后阶段释放锁资源

img

使用2pc 完成分布式事务有这两种情况:

  • 理想情况下:若所有的参与者都返回同意的消息,那么事务管理器就知道所有的参与者都已经准备好了,协调者就会向所有的参与者发回一个提交的消息,参与者在收到提交消息之后,会将本地事务进行提交,并且释放占用的资源,在处理完成之后,会返回一个完成的消息,分布式事务也就完成了。
  • 异常情况下: 假如其中的一个参与者出现了异常,这时候会向事务管理器发送终止消息,然后事务管理器收到回滚请求后,会将所有的操作进行撤销,恢复到事务启动前的状态,分布式事务执行失败。

看起来是没有问题,但是它肯定存在很多缺点:

  • 1、事务管理器挂掉了怎么办?整个分布式就没办法继续执行
  • 2、假设某个参与者的提交消息因为网络中断了,请求没有到达,这个也没有发送异常消息回来,那么事务就执行失败了。

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

  • 1、预备阶段:协调者向参与者发送 commit 请求,参与则如果可用就返回 yes、或no 。
  • 2、预提交阶段:发送请求后执行事务操作,将信息记录到事务日志中。如果某个协调者没有执行,就中断事务
  • 3、真正提交:该过程来进行最终的事务执行或中断事务操作。

但是 2pc 和 3pc 都无法彻底解决分布式的一致性问题。这个理论在这里就不过多描述了。作为了解即可。

二、解决方案

2.1 XA 方案

两阶段提交是在数据库层面实现的,例如 Oracle、Mysql 都支持 2PC 协议

它是多段式事务的变种,MySQL的事务模型就是基于这张图

1. app发起事务,进入事务管理器

2. 事务管理器TM通知资源管理器RM准备执行具体业务,执行完毕后通知TM,业务已经OK

3. TM收到全部RM的OK后,就通知它们提交事务

image-20211117183317961

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

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

XA 方案存在的问题:

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

2.2 Seata 方案

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

Seata 中有三大模块,分别是 TM、RM 和 TC。其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。

img

角色划分:

TM:事务管理器,开启、 提交、回滚分布式事务

RM: 资源管理器,注册、 汇报、执⾏资源

TC : 事务管理器服务功能,存储事务日志、补偿异常事务等、集中管理事务全局锁(全局行锁),seata服务端

事务执行整体流程:

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

2.3 方案对比

  • 架构层次:传统的 2PC 方案的 RM 实际上是在 数据库层,RM 本质上就是数据库自身,通过 XA 协议实现。而 Seata 的RM 是以 Jar 包的形式作为中间件层部署在应用程序这一侧的。
  • 两阶段提交:传统的2pc 无论第二阶段的决议是 commit 还是 rollback,事务资源的锁都要保持到第二阶段完成才释放,而Seata 的做法是在 第一阶段就将本地事务提交,这样就省去了锁占有的时间,整体提示效率。