理解两阶段提交,需要首先了解 XA 协议。
XA定义:XA是由X/Open组织提出的分布式事务的规范。主要定义了**(全局)事务管理器TM和(局部)资源管理器(RM)**之间的接口,主流的关系型 数据库产品都是实现了XA接口的
两阶段提交(Two-phase Commit Protocol,简称 2PC)针对的是刚性事务,将一个分布式的事务过程拆分成两个阶段: 投票 和 事务提交 ,是一个非常经典的强一致、中心化的原子提交协议
流程
AP 向 TM 提交请求,发起分布式事务
第一阶段 准备阶段(Prepare Phase)

准备阶段,主要目的在于打探数据库集群中的各个 RM 是否能够正常的执行事务,具体步骤如下:
- TM 向所有的 RM 发送事务预处理请求
REQUEST-TO-PREPARE
,并等待 RM 反馈事务执行结果(准备结果) - RM 收到请求之后,执行询问发起为止的所有事务操作,并将 Undo 信息和 Redo 信息写入日志
- RM 响应 TM 发起的询问。如果 RM 第二步 执行成功,则返回
PREPARED
;否则返回NO
。同时阻塞等待 TM 的后续指令
第一阶段准备阶段也被称作投票阶段,即各 RM 投票是否要继续接下来的提交操作
这里就会存在一些问题:
-
TM 发送请求部分 RM 没有收到
答:RM 会阻塞等待,而 TM 也会因为收不到回复而阻塞等待。解决方案,提供超时机制, TM超时回滚或咨询事务执行结果逻辑
-
RM 收到请求是如何准备的
答:特殊处理机制,看下面的 MySQL 执行 XA 命令
-
RM 收到请求之后执行了准备操作但是没有响应
答:TM 会阻塞,解决方案,提供超时机制, TM超时回滚或咨询事务执行结果逻辑
-
TM 等待响应部分或全部超时如何处理
答:TM 会阻塞,解决方案,提供超时机制, TM超时回滚或咨询事务执行结果逻辑
可惜的是,当 TM 无法收到所有 RM 的回复的时候,TM 会陷入阻塞!!需要超时逻辑进行下一步处理
在具体应用中超时/失败场景可以根据实际的系统需要而进行方案设计,这里的协议仅仅做了流程上的考量
- 超时重试:TM 可以尝试重新发送准备请求给失败的 RM,设定一个合理的超时时间。如果在超时时间内收到了 RM 的准备就绪通知,那么可以继续进行提交阶段。如果超时后仍未收到响应,可以将 RM 标记为失败,并回滚事务。
- 回滚事务:如果准备请求发送失败,可以将事务标记为回滚,并通知所有 RM 回滚事务。这样可以确保所有 RM 处于一致的状态,即使其中一部分 RM 未能接收到准备请求。
- 异常处理:如果准备请求的发送失败是由于网络故障、RM 崩溃或其他不可预见的错误引起的,可以捕获异常并进行相应的处理。可以根据具体的系统需求,选择适当的策略,如重试、回滚或者向管理员报告问题
RM 支持 XA 协议,在收到 TM 请求之后,可以根据 MySQL 命令看看 RM 是如何处理的
1 | // 第一阶段 |
第二阶段 提交阶段(Commit Phase)
在第一阶段 TM 收到所有 RM 返回成功的情况下,流程如下所示

-
如果所有的 RM 都回复的是
PREPARED
, 那么 TM 向所有 RM 发送COMMIT
消息; -
否则 TM 向所有回复
PREPARED
的 RM 发送ABORT
消息; -
RM 如果收到 TM 发来的
COMMIT
消息则提交,ABORT
消息则回滚,并向 TM 发送DONE
消息以确认
不懂就问:
-
部分 RM 并没有收到 TM 的提交或者回滚、
答:数据可能出现不一致。解决方案,可以引入咨询机制查看事务是否正常,阻塞时间更长
-
TM 等待 RM 的提交响应超时如何处理。
答:TM 无法知道执行结果,可能出现不一致,解决方案,可以引入咨询机制查看事务是否正常,阻塞时间更长
-
TM 作为事务协调者,是否存在单点故障以及性能瓶颈。
答:可以通过协商选举一个出来(如果能保存未提交事务让备TM 继续咨询协调更好)
当TM 等待响应部分超时或者失败,TM 均认为 RM 无法成功执行事务,为了整个集群数据的一致性,向各个 RM 发送事务回滚通知:
- TM 向各个 RM 发送事务
rollback
通知,请求回滚事务 - RM 收到事务回滚通知之后执行
rollback
操作,然后释放占有的资源 - RM 向 TM 返回事务
rollback
结果信息(发送也可能失败)
不懂就问:
-
部分RM 并没有收到回滚通知怎么办?
答:所有处于执行了操作但是未提交状态的 RM 都会陷入阻塞情况.
总结
优点:
- 两阶段提交支持不同数据库的分布式事务,比如一个是 MySQL,另外一个是 Oracle
- 业务无侵入:XA 模式将是业务无侵入的,不给应用设计和开发带来额外负担
- 数据库的支持广泛:XA 协议被主流关系型数据库广泛支持,不需要额外的适配即可使用
缺点:
- 同步阻塞,无论是在第一阶段的过程中,还是在第二阶段,所有 RM 资源和 TM 资源都是被锁住的,只有当所有 RM 准备完毕,TM 才会通知进行全局提交,RM 进行本地事务提交后才会释放资源。这样的过程会比较漫长,对性能影响比较大。
- 单点故障,一旦 TM 发生故障。RM 会一直阻塞下去。尤其在第二阶段,TM 发生故障,那么所有的 RM 还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是 TM 挂掉,可以重新选举一个TM ,但是无法解决因为 TM 宕机导致的 RM 处于阻塞状态的问题)
- 数据不一致。当只有部分 RM 收到commit请求,会导致整个分布式系统便出现了数据部一致性的现象。
- 脑裂,当 TM 发出
commit
消息之后宕机,而接收到这条消息的 RM 同时也宕机了。那么即使 TM 通过选举协议产生了新的TM ,这条事务的状态也是不确定的,没人知道事务是否被已经提交