zoukankan      html  css  js  c++  java
  • 分布式理论(四)—— 一致性协议之 3PC

    前言

    我们说为了实现 BASE 理论,需要在可用性和一致性之间找到一个合适的一致性理论,于是,我们在上篇文章中了解了 2PC 理论,也就是两阶段提交,二阶段提交原理简单,实现方便,但是缺点则是同步阻塞,单点问题,数据不一致,过于保守。

    而为了弥补二阶段提交的缺点,研究者们在他的基础上,提出了三阶段提交。

    1. 什么是三阶段提交

    3PC,全称 “three phase commit”,是 2PC 的改进版,其将 2PC 的 “提交事务请求” 过程一分为二。

    回忆一下 2PC 的过程:

    image.png

    也就是说,3PC 将阶段一 "提交事务请求" 分成了2部分,总共形成了 3 个部分:

    1. CanCommit
    2. PreCommit
    3. do Commit

    如下图所示:

    3PC

    2. 阶段一:CanCommit

    第一个阶段: CanCommit

    1. 事务询问:协调者向所有的参与者发送一个包含事务内容的 canCommit 请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应。

    2. 各参与者向协调者反馈事务询问的响应:参与者接收来自协调者的 canCommit 请求,如果参与者认为自己可以顺利执行事务,就返回 Yes,否则反馈 No 响应。

    3. 阶段 二:PreCommit

    协调者在得到所有参与者的响应之后,会根据结果执行2种操作:执行事务预提交,或者中断事务。

    1. 执行事务预提交分为 3 个步骤:
    • 发送预提交请求:协调者向所有参与者节点发出 preCommit 的请求,并进入 prepared 状态。
    • 事务预提交:参与者受到 preCommit 请求后,会执行事务操作,对应 2PC 中的 “执行事务”,也会 Undo 和 Redo 信息记录到事务日志中。
    • 各参与者向协调者反馈事务执行的结果:如果参与者成功执行了事务,就反馈 Ack 响应,同时等待指令:提交(commit) 或终止(abor)。
    2. 中断事务也分为2个步骤:
    • 发送中断请求:协调者向所有参与者节点发出 abort 请求 。
    • 中断事务:参与者如果收到 abort 请求或者超时了,都会中断事务。

    4. 阶段三:do Commit

    该阶段做真正的提交,同样也会出现两种情况:

    1. 执行提交
    • 发送提交请求:进入这一阶段,如果协调者正常工作,并且接收到了所有协调者的 Ack 响应,那么协调者将从 “预提交” 状态变为 “提交” 状态,并向所有的参与者发送 doCommit 请求 。
    • 事务提交:参与者收到 doCommit 请求后,会正式执行事务提交操作,并在完成之后释放在整个事务执行期间占用的事务资源。
    • 反馈事务提交结果:参与者完成事务提交后,向协调者发送 Ack 消息。
    • 完成事务:协调者接收到所有参与者反馈的 Ack 消息后,完成事务。
    2. 中断事务

    假设有任何参与者反馈了 no 响应,或者超时了,就中断事务。

    • 发送中断请求:协调者向所有的参与者节点发送 abort 请求。
    • 事务回滚:参与者接收到 abort 请求后,会利用其在二阶段记录的 undo 信息来执行事务回滚操作,并在完成回滚之后释放整个事务执行期间占用的资源。
    • 反馈事务回滚结果:参与者在完成事务回滚之后,想协调者发送 Ack 消息。
    • 中断事务:协调者接收到所有的 Ack 消息后,中断事务。

    注意:一旦进入阶段三,可能会出现 2 种故障:

    1. 协调者出现问题
    2. 协调者和参与者之间的网络故障

    一段出现了任一一种情况,最终都会导致参与者无法收到 doCommit 请求或者 abort 请求,针对这种情况,参与者都会在等待超时之后,继续进行事务提交。

    5. 总结:

    优点:相比较 2PC,最大的优点是减少了参与者的阻塞范围(第一个阶段是不阻塞的),并且能够在单点故障后继续达成一致(2PC 在提交阶段会出现此问题,而 3PC 会根据协调者的状态进行回滚或者提交)。

    缺点:如果参与者收到了 preCommit 消息后,出现了网络分区,那么参与者等待超时后,都会进行事务的提交,这必然会出现事务不一致的问题。

  • 相关阅读:
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/stateis0/p/9062128.html
Copyright © 2011-2022 走看看