Two‐Phase Commit - tenji/ks GitHub Wiki

两阶段提交

二阶段提交(Two-phase Commit)是指在计算机网络以及数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法。通常,二阶段提交也被称为是一种协议(Protocol)。它通常用于协调和同步数据库中的事务,确保所有更改都已提交或全部不提交,从而提供原子性和持久性属性。

一、历史

两阶段提交由 E. A. Hauck 在 20 世纪 60 年代首次提出。此后,它被广​​泛应用于各种用途,包括数据库管理系统分布式应用程序,甚至区块链技术

二、核心组件

  • Coordinator:负责发起事务并在参与者之间进行协调的中心节点;
  • Participants:执行事务并报告其是否已准备好提交或中止的节点。

三、前提

二阶段提交算法的成立基于以下假设:

  1. 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Participants)。且节点之间可以进行网络通信;
  2. 所有节点都采用预写式日志(WAL),且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失;
  3. 所有节点不会永久性损坏,即使损坏后仍然可以恢复。

四、基本算法

第一阶段(提交请求)

  1. 协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。
  2. 参与者节点执行询问发起为止的所有事务操作,并将 Undo 信息Redo 信息 写入日志。
  3. 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个"同意"消息;如果参与者节点的事务操作实际执行失败,则它返回一个"中止"消息。

有时候,第一阶段也被称作投票阶段,即各参与者投票是否要继续接下来的提交操作。

第二阶段(提交执行阶段)

成功

当协调者节点从所有参与者节点获得的响应消息都为"同意"时:

  1. 协调者节点向所有参与者节点发出"正式提交"的请求。
  2. 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送"完成"消息。
  4. 协调者节点收到所有参与者节点反馈的"完成"消息后,完成事务。

失败

如果任一参与者节点在第一阶段返回的响应消息为"终止",或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

  1. 协调者节点向所有参与者节点发出"回滚操作"的请求。
  2. 参与者节点利用之前写入的 Undo 信息执行回滚,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送"回滚完成"消息。
  4. 协调者节点收到所有参与者节点反馈的"回滚完成"消息后,取消事务。

有时候,第二阶段也被称作完成阶段,因为无论结果怎样,协调者都必须在此阶段结束当前事务。

基本流程图

基本流程图

五、状态转换

状态转换

六、问题和挑战

两阶段提交存在以下几个问题:

  1. 同步阻塞问题:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。也就是说从投票阶段到提交阶段完成这段时间,资源是被锁住的。
  2. 单点故障:由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞下去(因为 2PC 只有协调者有超时机制,参与者没有)。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。
  3. 数据不一致问题:在 2PC 最后提交阶段中,当协调者向参与者发送 commit 请求之后,发生了局部网络异常或者在发送 commit 请求过程中协调者发生了故障,这会导致只有一部分参与者接受到了 commit 请求。而在这部分参与者接到 commit 请求之后就会执行 commit 操作。但是其他部分未接到 commit 请求的机器则无法执行事务提交,于是整个分布式系统便出现了数据不一致性的现象。

∞、参考链接