分布式一致性协议之2PC和3PC

因为分布式系统的各个服务可能分布在不一样的节点上,若是各节点直接没有相互的通讯获取其余节点状态,那么各个节点是没法知道其余节点的任务处理结果的。算法

若是在分布式系统中发起一个事务,该事务涉及多个不一样节点,那么为了保证事务 ACID 特性,就须要引入一个协调者来统一调度事务涉及的多个节点,被调度的节点称为事务参与者。由此衍生出 2PC 和 3PC 协议,本文就来详细介绍 2PC 和 3PC 的工做机制。数据库

2PC(两阶段提交,Two-Phase Commit)

顾名思义,分为两个阶段:Prepare 和 Commit网络

Prepare:提交事务请求

基本流程以下图:架构

2PC1.png

  1. 询问 协调者向全部参与者发送事务请求,询问是否可执行事务操做,而后等待各个参与者的响应。app

  2. 执行 各个参与者接收到协调者事务请求后,执行事务操做(例如更新一个关系型数据库表中的记录),并将 Undo 和 Redo 信息记录事务日志中。分布式

  3. 响应 若是参与者成功执行了事务并写入 Undo 和 Redo 信息,则向协调者返回 YES 响应,不然返回 NO 响应。固然,参与者也可能宕机,从而不会返回响应。设计

Commit:执行事务提交

执行事务提交分为两种状况,正常提交和回退。3d

正常提交事务

流程以下图:日志

2PC2.png

  1. commit 请求 协调者向全部参与者发送 Commit 请求。cdn

  2. 事务提交 参与者收到 Commit 请求后,执行事务提交,提交完成后释放事务执行期占用的全部资源。

  3. 反馈结果 参与者执行事务提交后向协调者发送 Ack 响应。

  4. 完成事务 接收到全部参与者的 Ack 响应后,完成事务提交。

中断事务

在执行 Prepare 步骤过程当中,若是某些参与者执行事务失败、宕机或与协调者之间的网络中断,那么协调者就没法收到全部参与者的 YES 响应,或者某个参与者返回了 No 响应,此时,协调者就会进入回退流程,对事务进行回退。流程以下图红色部分(将 Commit 请求替换为红色的 Rollback 请求):

2PC4.png

  1. rollback 请求 协调者向全部参与者发送 Rollback 请求。

  2. 事务回滚 参与者收到 Rollback 后,使用 Prepare 阶段的 Undo 日志执行事务回滚,完成后释放事务执行期占用的全部资源。

  3. 反馈结果 参与者执行事务回滚后向协调者发送 Ack 响应。

  4. 中断事务 接收到全部参与者的 Ack 响应后,完成事务中断。

2PC 的问题

  1. 同步阻塞 参与者在等待协调者的指令时,实际上是在等待其余参与者的响应,在此过程当中,参与者是没法进行其余操做的,也就是阻塞了其运行。 假若参与者与协调者之间网络异常致使参与者一直收不到协调者信息,那么会致使参与者一直阻塞下去。

  2. 单点 在 2PC 中,一切请求都来自协调者,因此协调者的地位是相当重要的,若是协调者宕机,那么就会使参与者一直阻塞并一直占用事务资源。

    若是协调者也是分布式,使用选主方式提供服务,那么在一个协调者挂掉后,能够选取另外一个协调者继续后续的服务,能够解决单点问题。可是,新协调者没法知道上一个事务的所有状态信息(例如已等待 Prepare 响应的时长等),因此也没法顺利处理上一个事务。

  3. 数据不一致 Commit 事务过程当中 Commit 请求/Rollback 请求可能由于协调者宕机或协调者与参与者网络问题丢失,那么就致使了部分参与者没有收到 Commit/Rollback 请求,而其余参与者则正常收到执行了 Commit/Rollback 操做,没有收到请求的参与者则继续阻塞。这时,参与者之间的数据就再也不一致了。

    当参与者执行 Commit/Rollback 后会向协调者发送 Ack,然而协调者不管是否收到全部的参与者的 Ack,该事务也不会再有其余补救措施了,协调者能作的也就是等待超时后像事务发起者返回一个“我不肯定该事务是否成功”。

  4. 环境可靠性依赖 协调者 Prepare 请求发出后,等待响应,然而若是有参与者宕机或与协调者之间的网络中断,都会致使协调者没法收到全部参与者的响应,那么在 2PC 中,协调者会等待必定时间,而后超时后,会触发事务中断,在这个过程当中,协调者和全部其余参与者都是出于阻塞的。这种机制对网络问题常见的现实环境来讲太苛刻了。

3PC(三阶段提交,Three-Phase Commit)

上面说明了 2PC 协议的多个缺点,那么 3PC 就是在 2PC 的基础上,为了解决 2PC 的某些缺点而设计的,3PC 分为三个阶段:CanCommit,PreCommit 和 doCommit。

CanCommit

流程以下图:

3PC1.png

  1. 事务询问 协调者向全部参与者发送事务 canCommit 请求,请求中包含事务内容,询问是否能够执行事务提交操做,并开始等待响应。

  2. 反馈询问结果 参与者收到 canCommit 请求后,分析事务内容,判断自身是否能够执行事务,若是能够,那么就返回 Yes 响应,进入预备状态,不然返回 No 响应。

    注意:此过程当中并无执行事务(对比 2PC 的 Prepare 阶段,参与者是执行了事务的)。

PreCommit

流程图以下:

3PC2.png

PreCommit 阶段根据各参与者返回的 CanCommit 响应,决定下一步动做。若是收到了全部参与者的 Yes 响应,则执行事务预提交,不然(收到了至少一个 No 响应或必定时长内没有收到全部参与者的 Yes 响应,如 3PC 第一张图片中红色部分),执行事务中断。

事务预提交

  1. 发送 PreCommit 请求 协调者发送 PreCommit 请求,并进入 Prepared 阶段。

  2. 参与者处理 PreCommit 参与者收到 PreCommit 请求后,执行事务操做,并将 Undo 和 Redo 信息记录事务日志中。

  3. 反馈执行结果 若是参与者成功执行了事务并写入 Undo 和 Redo 信息,那么反馈 Ack 给协调者,并等待下一步指令。

事务中断

上图中,红色的 Abort 表示协调者发送的不是 PreCommit 请求,而是 Abort 请求。

  1. 发送事务中断请求 协调者向全部参与者发送 Abort 请求。

  2. 中断事务 参与者收到 Abort 请求后,会触发事务中断。此外,若是参与者在等待协调者指令超时,会本身触发事务中断,在 2PC 中,参与者会一直阻塞的等待协调者指令,因此 3PC 中解决了由于这种状况带来的阻塞。

doCommit

流程图以下:

3PC3.png

协调者根据第二阶段的响应决定最终操做,若是协调者收到了全部参与者在 PreCommit 阶段的 Ack 响应,那么会进入执行事务提交阶段,不然执行事务中断。

事务提交

  1. 发送提交请求 协调者收到全部参与者在 PreCommit 阶段返回的 Ack 响应后,向全部参与者发送 doCommit 请求,并进入提交状态。

  2. 事务提交 参与者收到 Commit 请求后,执行事务提交,提交完成后释放事务执行期占用的全部资源。

  3. 反馈结果 参与者完成事务提交以后,向协调者返回 Ack 响应。

  4. 完成事务 协调者收到全部参与者的 Ack 响应后,完成事务。

事务中断

  1. 发送事务中断请求 协调者向全部参与者发送 Abort 请求。

  2. 事务回滚 参与者收到 Abort 请求后,会使用第二阶段记录的 Undo 信息进行事务回滚,并在完成回滚后释放全部事务资源。

    注意:由于第一阶段并无任何参与者实际执行事务,因此在第二阶段(PreCommit 阶段)执行事务中断,是不须要事务回滚的,也就不须要下面的反馈结果,直接中断事务便可。

  3. 反馈回滚结果 参与者执行事务回滚后向协调者发送 Ack 响应。

  4. 中断事务 协调者接收到全部参与者反馈的 Ack 响应后,完成事务中断。

3PC 的改进和缺点

改进

  1. 下降了阻塞

    • 参与者返回 CanCommit 请求的响应后,等待第二阶段指令,若等待超时,则自动 abort,下降了阻塞;

    • 参与者返回 PreCommit 请求的响应后,等待第三阶段指令,若等待超时,则自动 commit 事务,也下降了阻塞;

  2. 解决单点故障问题

    • 参与者返回 CanCommit 请求的响应后,等待第二阶段指令,若协调者宕机,等待超时后自动 abort,;

    • 参与者返回 PreCommit 请求的响应后,等待第三阶段指令,若协调者宕机,等待超时后自动 commit 事务;

缺点

数据不一致问题仍然是存在的,好比第三阶段协调者发出了 abort 请求,而后有些参与者没有收到 abort,那么就会自动 commit,形成数据不一致。

总结

从上面讲述来看,2PC 和 3PC 都没法完美解决分布式数据一致性问题,虽然没法保证事务的 ACID 特性,但两阶段的思想在不少实际架构中有这普遍应用,例如 JTA 事务以及一些数据库的数据同步。

引用一句话,是 Google Chubby 做者说的:

“There is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos.”

Paxos 是兰伯特提出的一个解决分布式一致性的算法,后面再写文讲述其原理。

相关文章
相关标签/搜索