04、分布式事务-二阶段+三阶段提交协议

章节归属

分布式事务系列

二阶段提交的作用

二阶段提交是为了要保证分布式事务的原子性,理解这里的原子性:通过协调准备、执行两步操作,整个过程要么成功,要么失败回滚,对外部来说,该事务的状态变化是原子的。

二阶段提交的角色

概念解释比较抽象,边看边理解即可。

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

XA规范

是X/Open DTP定义的事务协调者 与 数据库 之间的接口规范,即 TC <--XA--> RM;事务些调整通过这个XA规范来通知数据库事务的开始、结束(提交/回滚)
XA规范的实现 由数据库厂商提供。

二阶段提交的工作流程

整个流程是TC和 多个RM之间的一个互动的过程,简单来说就是【预备->跑】 这样两个过程,即准备和执行两个阶段:

  1. 准备阶段:TC通知每个RM准备,RM开始执行分支事务,但是不提交,相关资源会被锁;每个RM给TC反馈已准备就绪,等待下一步的提交指令进行分支事务提交。
  2. 提交阶段:TC通知每个RM提交分支事务,RM完成分支事务提交后,释放资源并反馈TC;TC确认所有RM的分支事务完成后,流程结束
image.png
二阶段提交的角色解读
image.png
  1. TM即其实整个事务的发起者,这个发起者内的逻辑决定了本次大事务覆盖的分支事务有哪些,其执行逻辑控制着整个大事务的开始、结束(提交/回滚)
  2. 由于每个RM(数据库)可以保证自己数据库中的分支事物,但不能保证除自己以外的其他RM(数据库)的分支事务,因此需要第三方(TC)介入协调;
  3. 理论上这个TC可以是由TM自己来兼职,但从职责边界的角度看,如果TC是独立的,那么TM和RM就会变得很轻巧,TC的功能也会更内聚,也更容易通过集群部署提升可用性。

二阶段提交的异常流程

image.png

TC通知每个RM准备,其中部分RM反馈准备阶段出错;或者TC在规定时间内没收到所有RM完成准备的反馈; TC要发起回滚通知每个RM。

因天然的存在网络和设备问题,会导致TC 和 RM 出现异常:

    1. TC异常:
    • 1.1 TC发出【准备】指令前出问题,对RM无影响,因为RM都未开始事务,不占用RM的资源
    • 1.2 TC发出【准备】指令后【提交】指令前,TC出问题,各RM开始执行事务并挂起等待下一步的提交指令,相关的资源会被锁定,其他的事务若要操作被锁定的资源也需等待;
    • 1.3 TC发出【提交】指令后,TC出问题,若部分RM异常,那就出现了部分RM正常执行,部分RM未正常执行,即产生了数据不一致的问题。
    1. RM出问题
    • 2.1 TC发出准备指令后,部分RM反馈准备阶段出错,或者TC在规定时间内没收到所有RM完成准备的反馈; TC要通知每个RM回滚。
    • 2.2 TC发布提交指令后,部分RM出问题,那么也会产生数据的不一致问题

二阶段的缺陷

所有问题可以归为以下三种:

  1. 协调者故障:
    需通过集群高可用来规避单机故障
  2. 性能问题(资源利用率低):
    等待指令,如果遇到网络或节点问题,会导致长时间等待,处于挂起状态;需要通过增加超时自省机制,来限制挂起时间,并指定超时后的默认处理
  3. 数据不一致:
    这个没有绝对的保证,只能尽量。通过【鸵鸟算法】了解更多。

三阶段提交协议

正常流程
  1. can commit: TC协调所有RM进行预检,预检过程不锁定资源
  2. pre commit:收到所有RM的can commit的正常反馈后,TC通知所有RM开启并执行事务但不提交事务
  3. do commit:收到所有RM的pre commit的正常反馈后,TC通知所有RM提交事务
image.png
关键设计

目标是通过引入以下逻辑来修复二阶段的缺陷:

  1. 引入预检环节,避免在不具备锁定资源的条件下锁定资源
  2. 在TC和RM中都引入超时机制,超时后自醒,主动执行自认为合理的下一步逻辑(回滚或者提交),避免无上限的挂起:
    2.1 TC端,遇到超时就给RM发abort指令,中断整个事务
    2.2 RM端,在收到can commit 后,pre commit之前,超时自醒后直接中断RM的分支事务
    2.3 RM端,在收到pre commit 指令后,等待下一步的do commit指令超时,直接提交事务(大概率是正确的选择,但如果是错误的选择就导致了数据的不一致)
image.png

异常流程

1. can commit阶段:
  • 部分RM直接反馈不能开始事务,TC向所有RM发送abort请求。
  • TC等待反馈超时,TC向所有RM发送abort请求。
  • RM预检没问题,但一直无法接收到下一步的的指令(反馈can commit超时 或接收TC 下一步指令超时),执行事务的中断
  • RM收到来自TC的abort请求之后执行事务的中断;
image.png
2. pre commit阶段
  • TC收到RM反馈异常,向所有RM发送abort请求,执行回滚
  • TC等待反馈超时,向所有RM发送abort请求,执行回滚
image.png
3. do commit阶段
  • RM收到pre commit指令并正常执行事务,给TC反馈pre commit完成后,理论上是要等待下一步的do commit指令后才提交事务;但是如果未能等到下一步的do commit指令超时了,会自主提交事务。因为经过预检通过,执行到这个阶段整个事务成功的概率已经很高了;
  • 部分RM 执行pre commit异常,部分RM 执行 pre commit 正常,但此时TC挂了,那么通过RM的超时自醒机制,就出现部分RM提交,部分RM回滚,出现数据不一致。
  • 另外一种情况,TC发送了abort 指令,RM超时未收到指令就提交了事务,其他RM收到了TC发送的abort指令后执行了回滚,会出现数据不一致。
三阶段的优缺点

优点:通过预检,避免了资源的无效占用;TC端和RM端各自的超时自醒处理,避免长时间资源占用不释放。提高资源利用率
缺点:多出了一个流程,增加了复杂度;依然有数据不一致的问题

参考


  1. DTP模型之一:(XA协议之一)XA协议、二阶段2PC、三阶段3PC提交
  2. 基于XA协议的两阶段提交2PC.mp4
  3. 分布式事务解决方案专题

你可能感兴趣的:(04、分布式事务-二阶段+三阶段提交协议)