精华内容
下载资源
问答
  • 二阶段提交存在问题
    千次阅读
    2022-04-13 16:59:17

    二阶段提交(2 Phase Commitment Protocol)
    为了使分布式系统架构下的各个节点在进行事务提交时保持一致性的一种协议。二阶段提交通过协调者和各个参与者的配合,实现分布式一致性。

    角色

    1. 协调者:调度事务
    2. 参与者:参与事务的执行和投票

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

    第二阶段:提交阶段
    当协调者从所有的参与者节点获得的相应消息都是"同意"时:
    1).协调者节点向所有参与者节点发出"正式提交(commit)"的请求
    2).参与者正式完成操作,并释放在整个事务期间占用的资源
    3).参与者节点向协调者节点发送"ack完成"消息
    4).协调者收到所有参与者节点反馈的"ack完成"消息后,完成事务

    如果任一参与者节点在第一阶段返回的信息是"中止",或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应信息时,那么这个事务就会被回滚:
    1).协调者节点向所有参与者节点发出"回滚操作(rollback)"的请求
    2).参与者节点利用之前的Undo信息执行回滚,并释放在整个事务期间占用的资源
    3).参与者节点向协调者节点发送"ack回滚完成"信息
    4).协调者节点收到所有参与者节点反馈的"ack回滚完成"信息后,取消事务

    不管最后结果如何,第二阶段都会结束当前事务。

    2 PC存在的问题

    1. 性能问题:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
    2. 可靠性问题:参与者发生故障。协调者需要给每个参与者额外指定超时机制,超时后整个事务失败。协调者发生故障。参与者会一直阻塞下去。
    3. 数据一致性问题:二阶段无法解决的问题:协调者在发出
      commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

    2PC的优点
    尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。(其实也不能100%保证强一致)

    更多相关内容
  • 正确理解二阶段提交(Two-Phase Commit)

    万次阅读 多人点赞 2019-03-07 15:42:56
    二阶段提交出现的背景是, 当我们使用分布式系统时, 如果分布式系统中的机器发生故障之后, 如何保证事务数据的一致性。 从一个场景入手, 假设一个人要从 A 银行向 B 银行进行跨行转账 100 元。 此时我们需要对 A ...

    明确问题

    从一个场景入手, 假设一个人要从 A 银行向 B 银行进行跨行转账 100 元。

    此时我们需要对 A 银行数据库中该用户的账户,做金额扣减操作( - 100), 同时对 B 银行数据库中该用户的账户做金额增加操作 ( +100)

    这两个操作( -100 和 + 100) 我们希望它们是一个事务, 要么同时成功, 要么同时失败 。

    此时我们的目标是希望有一个

    • 原子性的提交协议 (Atomic Commit Protocol)

    草稿方案

    • 场景难点一:
      • A --> B : 你提交我就提交
      • B 不理 A
      • 然后 ?
      • A 和 B 都没有办法继续
        在这里插入图片描述

    先提出一种拍脑门方案, 设置一个事务协调者( Transaction Coordinator)。

    由该协调者分别向 A 银行 , B银行发送指令, 发送完毕后直接予以返回成功

    在这里插入图片描述

    显然, 上述方案会出现很多问题:

    • 问题一: A 银行余额不足
      • A 未提交事务, B 却成功提交
    • 问题二: B 银行账户不存在
      • A 提交事务, B 未提交
    • 问题三: TC 到 B 中间的网络发生中断
      • A 提交, B 没提交
    • 问题四: TC 在给 B 发送指令前宕机
      • A 提交, B 没提交

    原子提交协议希望实现的2个特性

    由上面的场景, 我们可以总结出所有原子提交协议希望实现的2个特性

    • 安全性(Safety)
      • 如果任意一方 commit, 所有人必须都 commit
      • 如果任意一方中断,则没有任何一个人进行 commit
    • 存活性(Liveness)
      • 没有宕机或失败发生时, A 和 B 都能提交, 则提交
      • 如果发生失败时,最终能达成一个一致性结果(成功/失败), 予以响应, 不能一直等待

    正确的二段提交协议(Two-Phase Commit)

    在这里插入图片描述

    TC 发送 “prepare” 给 A 和 B
    等待响应结果
    A 和 B 均返回 Yes
    A 和 B 任意一个返回 No
    TC 向 A 和B 发送 commit 指令, 向 client 发送 ok 响应
    TC 向 A 和B 发送 aboort 指令
    A 和 B 在收到 TC 发送的 commit 指令后, 执行 commit 操作

    上面的流程看似简单, 但是有一个点容易被忽略:

    • 当 TC 收到 A 和 B 响应 “Yes” 后, 做出了 “commit” 的决定, 向 A /B 发送指令或, 并不需要再等待 A/B 的响应, 可以直接向 client 返回成功
    • 之所以可以这样做的原因是, 当 A/B 返回 Yes 后, 就代表 A 和 B 都做好了提交准备, 只要 TC 决定要提交,即使 A/B 宕机, 没有收到 TC 的 Commit 指令, 只要 A/B 被修复重启, A 和 B 都必须有能力成功完成提交操作。

    二阶段提交协议如何满足安全性(Safety)

    • 事务协调者 TC,作为一个中心, 统一收集了 A 和 B 是否有意愿(有能力)进行 commit
    • 事务协调者 TC 强制保证了, A, B 双方必须都有意愿提交时, 才进行 commit

    二阶段提交协议如何满足存活性( Liveness)

    遗憾的是: 上面描述的协议无法满足存活性。

    下面分析一下这个协议在执行过程中可能面临哪些问题

    • 问题1: 响应超时
      • 结点正常运行, 但是没有正常收到它所期待的响应, 可能原因如下
        • 其他的结点故障了
        • 网络情况不好, 数据包丢失了或网络干脆中断了
    • 问题2: 重启
      • 结点宕机, 重启以后, 如何恢复被中断的操作

    如何应对超时

    首先分析整个协议里面有哪些等待操作?

    1. 事务协调者 TC 需要等待 A 和 B 返回 “yes”/“no” 才能进行下一步操作
      在这里插入图片描述
    2. A 和 B 需要等待 TC 发送 “commit”/ “abort” 指令, 才能进行下一步操作
      在这里插入图片描述

    然后分析等待状态超时的时候, 是否有办法继续协议

    • 事务协调者 TC 需要等待 A 和 B 返回 “yes”/“no” 超时:

      • 此时 , TC 还没有发送过任何 “commit” 指令
      • TC 此时可以安全地发起终止 “abort” 指令, 放弃 commit
        • 上面这种做法, 保证了安全性, 放弃了存活性
        • 因为 A, B 可能都做好了准备进行提交, 只是 “yes” 信息没有成功被 TC 收到, 就导致了整个事务无法提交
        • 这种情况属于本可以提交而未提交, 也就是说 TC 采取了非常保守的方案
    • A 和 B 需要等待 TC 发送 “commit”/ “abort” 指令 超时:

      • 以 B 为例进行考虑( A 的情形完全对称)
      • 如果 B 之前回复的是 “no” , 那此时, B 可以无需等待 TC 回复就放弃 commit 操作, 因为 TC 即使收到了响应, 也会回复 “abort”, 这个行为是统一的
      • 如果 B 之前回复了 “Yes”,那此时 B 能单方面地直接进行 aboort 操作吗?
        • 不行! 因为, TC 此时可能已经成功收到了 A, B 返回的 “Yes”, 并且已经向 A 发送了 “Commit”, 然后再向 B 发送 “commit” 前宕机了
        • 如果 B 放弃了 commit 操作, 就会出现 A 执行了 commit, B 未执行 Commit 的情形, 显然违背了安全性(Safety)
      • 那 B 能单方面地直接进行 commit 操作吗?
        • “不行” ! 因为 A 可能返回给TC 的响应是 “No”
      • 那此时应该怎么办?:
        • 方案一: B 一直等待 TC 的 “commit”/ “abort” 指令
        • 方案二(更好): B 针对这种情形发起一轮终止协议操作(Termination Protocol)

    超时终止协议

    • B 向 A 发送状态查询请求, 询问 A 是否知道事务已经提交
    • 如果 B没有收到 A 的响应, B 无法进行后续操作, 只能继续等待
    • 如果 B 收到了 A 的响应, 则分如下几种情况:
      • A 回复说 , 它已经收到了来自 TC 的 “commit”/ “abort” 指令
        • 此时 B 可以执行 “commit”/ “abort”, 应为 TC 发给 B 的指令肯定和 A 一样
      • A 回复说, 它还没有向 TC 回复 “yes”/“no”,
        • 此时 B 和 A 都直接执行 abort 操作
        • 不必担心 TC, 因为 TC 尚未收到 A 的回复, 最终会根据 A 和B 的状态回复 client
      • A 回复说, 它向 TC 回复了 “no”
        • 此时 B 和 A 都直接执行 abort 操作
      • A 回复说, 它向 TC 回复了 “yes”
        • 此时 B 不能进行后续操作
        • 因为 TC 可能已经收到了 A 和 B 的 “Yes” 响应, 并且决定执行 “commit”, 向 A 和 B 发送了“commit” 指令, 只是没被 A 和 B 收到, 但是 TC 发送 “commit” 之后就会直接向客户端返回了 “ok”
        • TC 也有可能在等待 A 和 B 的响应过程中超时了, 直接进行了 “abort” 决定, 向 A 和 B 发送了 “abort” 指令, 只是没被 A 和 B 收到, 但是 TC 发送 “abort” 之后就会直接向客户端返回了 “fail”

    如何应对宕机重启

    基本原则: 一旦 TC 决定了 commit , 那么任意一个结点都不允许发生回滚

    有如下几种情形需要考虑:

    • TC 在做出决定后, 立即宕机了, 没有吧 commit 指令成功发送给 A 和 B , 然后被重新启动
    • A 和/或 B 在发送 Yes 的过程中, 宕机了, 没有把 " Yes" 成功发送给 TC , 然后被重新启动

    如果所有的结点, 都能知道他们在宕机前的状态是什么, 那就有如下几种解决方案:

    • A 或 B 相互发起之前描述的终止协议 Termination Protocol, 即相互询问是否知道事务已经交
    • A 和 B 也可以向 TC 发起状态查询操作, TC 可能知道事务是否已经提交

    如何保证在宕机重启后, 依旧能够记得宕机前的状态:

    • 在发送任何信息给其他结点前, 一定要先行将自己要回复的内容写入磁盘, 这样可以保证一旦宕机, 可以知道宕机前的状态。
      • 对于 TC 而言, 在向 A 和 B 发送 “commit” 指令前, 一定要先行将 “commit” 成功记录到磁盘
      • 对于 A/B 而言, 在向 TC 发送 “yes” 之前, 一定要先行将 “yes” 记录成功记录到磁盘

    这样重启之后就可以进行如下的操作:

    • 对于TC, 重启以后, 如果发现磁盘中没有记录 “commit” , 那就可以直接进行 “abort” 操作
      • 磁盘中没有 “commit” , 就说明根本没向 A/B 发送过 “commit”, 此时是安全的
    • 对于 A 或者 B , 重启以后, 如果发现磁盘中没有记录 “yes” , 那就可以直接进行 “abort” 操作
      • 磁盘中没有 “yes” , 说明根本没有向 TC 发送过 “yes”, TC 不可能做出 “commit” 操作, 执行abort 是安全的
    • 对于 A或者 B, 重启以后, 如果发现磁盘中有 “yes” 记录, 那就可以发起终止协议 “termination protocol”
      • 终止协议有可能陷入继续的等待中
    • 如果TC, A, B 都发生了重启操作, 只要当 3 个结点都恢复以后, 就可以向 TC 发起查询, 查看TC 的磁盘中是否存在 “commit” 记录, 如果存在, 则均可进行 “commit” 操作

    二阶段提交实现的工程化难点

    准备阶段到底干了什么

    回顾之前的内容,可以发现, 二阶段提交协议(Two-Phase Commit)的核心是

    • 引入了一个事务协调者(TC)
    • 在真正的提交操作前, 增加了一个准备阶段, 收集业务结点是否有能力进行提交

    部分程序员可能会对其工程实现的一个关键点产生误解:

    • 准备阶段就是开启一个事务, 执行所有的业务代码, 都不报错, 不执行事务的 commit 操作, 然后向 TC 回复 “Yes”, 表示我已准备好提交

    这种做法并不满足二阶段提交协议对于准备操作的要求:

    • 二阶段提交协议中, 业务结点回复 “Yes” , 代表它做好了提交操作的所有准备, 只要结点回复了 “Yes”, 即使突然发生宕机, 只要结点重新启动, 收到了 TC 发送的 commit 指令, 必须依旧能正确提交
    • 普通数据库如果在在一个事务中间发生了宕机(比如数据库所在机器直接停电), 重启以后, 数据库的默认行为是对处于中间状态的事务进行回滚操作, 并不具备继续等待并接受 commit 指令的能力

    以之前提到的转账操作为例, 如果 A 银行需要对转账客户的账户执行 -100 元操作, 当它向 TC 回复了 “Yes” 前, 应该完成以下操作:

    • 确定账户上有 100 待扣减, 将这100 元冻结, 其他的操作无法解冻, 转移这100元。
    • 留下必要的持久化记录, 确保即使宕机重启, 收到 “abort” 指令也有能力回滚到100 元被冻结前的状态
    • 留下必要的持久化记录, 确保即使宕机重启, 收到 “commit” 指令也有能力正确提交, 完成 -100 元操作
    • 留下必要的持久化记录, 标识自己已经完成了准备阶段的所有操作, 要向 TC 回复 “Yes” 指令

    只有以上这些操作都成功完成以后, 银行 A 才能尝试向 TC 发送 “Yes” 指令,否则就有违二阶段提交协议

    事务协调者是第三方吗

    二阶段提交中, 除了准备阶段, 另一个显眼的角色就是事务协调者( Transaction Coordinator)。

    此时就会有部分同学产生困惑, 事务协调者是否一定得是一个独立的机器,处于独立的结点。

    答案: 并不是!

    从准备阶段的要求就可以看出。 二阶段提交协议的核心, 是描述了在每一步操作前, 每一种角色应该达到什么状态, 具备什么能力。 具体在工程实现中, 这几种角色分布在几个结点, 以什么方式去实现, 都是可以的。

    以前文所举的银行转账操作为例。

    客户端 client 发起一个转账操作请求给 TC, 这个 TC 完全可以就属于银行 A。 只要银行 A 实现的 TC 在银行 A 数据库发起 -100 元的操作前,依旧先按照协议要求;

    • 模拟 prepare 阶段, 进行持久化记录
    • 做好 -100 元随时提交或回退的准备

    即可以根据银行 B 的准备阶段应答结果, 进行后续的操作。

    二阶段提交协议(Two-Phase Commit)的总结

    二阶段提交所说的二阶段分别指: Prepare , Commit 两个阶段

    二阶段提交满足如下性质:

    • 安全性: 所有的结点最终会达成一致的决定
    • 安全性: 只有当所有人都说了 “yes”, 才会执行提交
    • 存活性: 如果没有宕机和信息丢失, 提交肯定可以完成
    • 存活性: 如果发生宕机和信息丢失, 只要最终修复, 并且重启, 等待足够长的时间, 最终一定可以达成某项一致的结果(abort 或者 commit)

    可能有同学会有疑问, 那如果宕机不能被修复, 那些处于中间状态的记录怎么办:

    1985 年 Fischer, Lynch, Paterson 提出了定理:

    no distributed asynchronous protocol can correctly agree in presence of crash-failures

    翻译一下就是

    在出现宕机时(最终没有修复并重启), 不存在一种分布式的异步协议可以正确地达成一致结果(同时提供安全性和存活性)。

    所以有故障发生, 不修复还想保证记录达成一致? 洗洗睡吧

    展开全文
  • 最近在看分布式事务,于是网上搜索相关资料,霎时间,对方给我扔来了一大堆概念,什么二阶段提交、三阶段提交、TCC补偿机制、CAP理论、ACID、BASE等等等,它们被零散地分散到各种各样的文章里。这里我根据自己所学习...

    1. 前言

    最近在看分布式事务,于是网上搜索相关资料,霎时间,对方给我扔来了一大堆概念,什么二阶段提交、三阶段提交、TCC补偿机制、CAP理论、ACID、BASE等等等,它们被零散地分散到各种各样的文章里。这里我根据自己所学习到的,以及所理解的方式,将这些概念放到一起谈一谈,一方面做个记录,一方面也希望可以帮助像鄙人一样的新手将这些概念有机地串连起来

    2. 正片开始

    话不多说,不再说那么多关于单机系统到分布式系统的介绍了,在分布式系统的设计中,有位大佬提出了CAP理论,根据CAP,也延伸出了ACID、BASE这些理论

    2.1. CAP

    C、A、P分别代表了3个特性,这个理论是说这个3个特性不能共存,只能共存2个,为什么呢?
    先假设一个分布式系统如下图所示
    简单的分布式系统架构
    接下来说说C、A、P各个特性

    2.1.1. C(consistency,一致性)

    写之后的读操作必须读到最新值
    如:S1、S2上有a=0,然后client向S1修改了a=1,此时client再去S2读取a也要等于1
    就是S1更改完值后要立即同步到S2
    不同角度看:

    • 客户端:并发来访问数据,都要能访问到最新值
    • 服务务端:某个服务里的数据变化了,要更新到整个分布式系统,保证各个服务的数据是一致的

    根据一致性程度分:

    • 强一致性:更新后的值会被立即同步到整个系统,这会导致同步时访问服务会被阻塞
    • 弱一致性:更新后的值没有立即同步到整个系统,但会在一定时间内同步好
    • 最终一致性:是特殊的弱一致性,即达到同步的这一段时间会比较长,但保证最终数据都是一致的
    2.1.2. A(availability,可用性)

    只要用户发起请求,就要立即给出反应,不能有操作失败 / 请求超时的情况

    2.1.3. P(partition tolerance,分区容错性)

    某个服务故障了,整体依旧可以对外提供服务,这是设计分布式系统的基础
    所以P在分布式系统中一般是必备的,不然就和单机系统没区别了

    2.1.4. 为什么3个特性不能共存

    先假设P存在,则C(一致性)和A(可用性)就会矛盾了
    注意:这里的一致性其实是针对强一致性,弱一致性和可用性还是可以共存的

    分区容错下,多个服务间通信一定会有网络问题

    • 满足强一致性时,一定会有数据同步的阻塞时间,导致客户端访问被阻塞,就达不到可用性了
    • 满足可用性时,客户端访问要立即返回,这时数据还没同步好,得到的是不一致的数据

    那假设P不存在,则CA可以共存,这就类似一个单机应用,没了分布式可言

    2.2. ACID

    这个大家都比较熟悉了,是关系型数据库事务的特性
    其实它也是满足CA的情况

    2.3. BASE

    这是CAP的延伸,权衡了可用性和一致性而提出的理论,相当于满足PA的情况

    为什么说相当于呢,因为并没有完全舍弃C,只是舍弃强一致性,保留了最终一致性

    下面说说BASE的各个特性

    2.3.1. BA(basically vavilable,基本可用)
    • 响应时间上:可能因为网络故障导致响应时间延长一点点
    • 功能上:由于某个服务突然被大量访问,那新来的访问被降级到其他服务,如返回网络繁忙等等
    2.3.2. S(soft state,软状态)

    允许系统中的某些数据处于中间状态,且这些中间状态不影响整体的可用性,即允许各个节点之间的数据同步存在延迟

    2.3.3. E(eventually consistent,最终一致性)

    不能保证每时每刻访问的都是最新的数据,但保证一段时间后,最终数据都是一致的

    2.4. 小结

    所以CAP、ACID、BASE说的都是分布式系统设计的理论,还没具体地说到分布式事务的相关理论
    从上面看来,貌似ACID、BASE是不能共存,不过在实际的系统设计中,根据各个功能的要求,有机地结合ACID、BASE,寻找最优的协调方案才是最合适的

    3. 进入分布式事务

    据我所知,现在实现分布式事务的设计方案应该有3种,分别就是二阶段提交、三阶段提交和TCC
    他们都有2种重要的角色【事务协调者】【参与者,也就是各个服务】

    3.1. 二阶段提交

    协调者 参与者集群 1.1 询问各个参与者是否可以正常执行事务 1.2 执行事务,不提交 1.3 反馈准备提交或回滚 2.1 通知所有参与者提交或回滚 2.2 事务提交或回滚 2.3 反馈结果 协调者 参与者集群
    3.1.1. 第一阶段

    准备阶段

    1.3反馈准备提交或回滚 存在多种情况

    • 所有参与者都反馈可以提交
    • 有参与者反馈回滚(不管多少)
    3.1.2. 第二阶段

    提交阶段

    2.1根据1.3的情况

    • 所有参与者都反馈可以提交–》通知全部提交
    • 有参与者反馈回滚–》通知全部回滚
    • 等待反馈超时–》通知全部回滚

    2.2根据2.1

    • 通知全部提交–》提交
    • 通知全部回滚–》回滚
    • 一直没收到请求–》阻塞住

    可能出现问题:
    ● 同步阻塞:参与者反馈1.3后是处于阻塞状态等待2.1,如果网络问题或协调者宕机了,接受不到2.1,那么会一直阻塞
    ● 数据不一致:部分参与者接受不到2.1,阻塞中,而接受到的就进行提交或回滚了,造成数据不一致

    3.2. 三阶段提交

    改进二阶段提交的缺点问题,得到了三阶段提交

    协调者 参与者集群 1.1 询问各个参与者是否可以正常执行事务 1.2 反馈是否可执行 2.1 准备提交 2.2 执行事务,不提交 2.3 反馈准备好提交或回滚 3.1 通知所有参与者提交或回滚 3.2 事务提交或回滚 3.3 反馈结果 协调者 参与者集群
    3.2.1. 第一阶段

    预判断

    1.2反馈情况

    • 所有参与者都反馈可以
    • 有参与者反馈不能成功执行(不管多少)
    3.2.2. 第二阶段

    准备提交

    2.1根据1.2的情况

    • 所有参与者都反馈可以–》通知全部准备提交
    • 有参与者反馈不能成功执行–》通知全部 abort 通知
    • 等待反馈超时–》通知全部 abort 通知

    协调者发起abort通知后就会进入结束状态了,不再进行后续
    2.2根据2.1

    • 通知全部准备提交–》执行事务,不提交
    • 通知全部 abort 通知–》会中断事务的操作
    • 等待超时–》会中断事务的操作
    3.2.3. 第三阶段

    提交阶段

    3.1根据2.3的情况

    • 所有参与者都反馈体可以提交–》通知全部提交
    • 有参与者反馈回滚或中断事务–》通知全部回滚
    • 等待超时–》通知全部回滚

    3.2根据3.1

    • 通知全部提交–》提交
    • 通知全部回滚–》回滚
    • 等待超时–》提交

    为什么第三阶段等待超时就会自动提交呢?
    因为经过了前面两阶段的判断,第三阶段可以提交的概率会大于回滚的概率

    3.3. 三阶段/二阶段差异

    三阶段的参与者是有超时机制的,等待请求超时会进行事务中断,或事务提交
    而二阶段不会超时,只会阻塞

    3.4. TCC

    数据库表需要存多两个字段【可更新数】【冻结数】
    将各个服务的事务执行分成3个步骤

    3.4.1. T(try,尝试更新阶段)
    • 原数据不变,只更新【可更新数】,同时保存变化差值在【冻结数】,方便回滚
    • 状态设置为【更新中】
    3.4.2. C(confirm,确认阶段)
    • 更新原数据,【可更新数】不变(在try阶段更新好了),清除【冻结数】
    • 状态设置为【更新完】

    此时表示业务正常完成了

    3.4.3. C(cancel,补偿还原阶段)

    如果try出错了,那各个服务就执行cancel还原数据,相当于回滚

    • 根据【可更新数】【冻结数】更新数据为事务前的样子
    • 状态设置为更新前的状态【未更新】

    如果是confirm或cancel出错了,一般会去重复执行
    因为过了try,可以认为confirm是一定可以执行成功的,除非重复执行次数达到阈值,就落地成日志,让人工处理
    在这里插入图片描述
    使用此方案需要我们在业务服务上实现【try】【confirm】【cancel】这3个接口
    注意:

    这里事务回滚的方式不像我们认为的那样 — 数据库直接给我们处理好
    而是通过【cancel】将数据补回去,所以TCC也叫【补偿机制】

    3.5. 小结

    二阶段提交、三阶段提交、TCC分别是三种实现分布式事务的方案
    至于具体的实现框架
    二阶段有mysql的XA事务,TCC有seata、tcc-transaction
    我们看TCC会涉及到服务与服务之间的接口调用,因为网络问题,极有可能出现重复调用的情况,所以【confirm】【cancel】这些接口应该要实现幂等
    当然服务间的通信除了通过【同步的rpc】,也可以通过【异步的MQ】来实现,所以引出了接下来的基于MQ最终一致性方案

    4. 基于MQ最终一致性方案

    使用异步mq来辅助服务间通信,在服务发消息到消息进入MQ这个过程中,有可能会出现网络不稳定的情况,导致问题
    根据事务执行和发消息的先后顺序,可分如下:

    • 先完成事务再发消息的情况:事务提交了,消息没发送成功
    • 先发消息再执行事务的情况:消息发送成功了,事务执行失败回滚了

    所以为了实现【事务提交】【消息发送成功】这两个操作是原子的,提出2种基于MQ最终一致性方案:

    • 使用无事务MQ的
    • 使用事务模型MQ的

    注意:可能会发生同个消息发送多次的情况,因此要求消费者在消费消息时做好幂等

    4.1. 无事务MQ

    需要为增加一张辅助表【事务记录表】,记录已提交的事务是否成功将消息发送到MQ
    还要加入一个定时程序,到期去扫描【事务记录表】,看看哪些事务提交了但还没发消息到MQ,便去处理发送
    在这里插入图片描述

    4.2事务模型MQ

    除了上面的做法,还可以直接使用已经实现了事务模型的MQ,如RocketMQ
    下面说说RocketMQ
    在这里插入图片描述
    1.half消息:在消息队列上开启事务,生产者给消息队列发送【半消息】(包含了完整的消息内容,只是对消费者还不可见)

    2.执行事务

    3.将事务的执行结果发送给消息队列

    • 提交:那么【半消息】就变成消费者可见的
    • 回滚:丢弃【半消息】

    4.1.如果消息队列等不到第3步的反馈,那么自己会定期去检查事务的执行情况

    4.2.根据事务执行情况决定【半消息】的去留

    5.【半消息】可见后即可被消费者消费

    5.总结

    以上就是鄙人对分布式事务中涉及的一些概念,通过自己的理解将他们放一起描述出来,如有错误,欢迎指正✧(≖ ◡ ≖✿)

    展开全文
  • MySQL 为什么需要两阶段提交

    千次阅读 2022-03-29 12:02:26
    什么是两阶段提交1.1 binlog 与 redologbinlogredo log1.2 两阶段提交2. 为什么需要两阶段提交3. 小结 为什么要两阶段提交?一阶段提交不行吗? 小伙伴们知道,MySQL 中的事务是两阶段提交,我们见到的很多分布式...


    为什么要两阶段提交?一阶段提交不行吗?

    小伙伴们知道,MySQL 中的事务是两阶段提交,我们见到的很多分布式事务也都是两阶段提交的,例如 Seata,那么为什么要两阶段提交呢?一次直接提交了不行吗?今天我们来聊聊这个话题。

    关于分布式事务 seata,不懂的小伙伴可以参考松哥之前的文章,传送门:

    1. 什么是两阶段提交

    1.1 binlog 与 redolog

    binlog

    binlog 我们中文一般称作归档日志,如果大家看过松哥之前发的 MySQL 主从搭建,应该对这个日志有印象,当我们搭建 MySQL 主从的时候就离不开 binlog(传送门:MySQL8 主从复制踩坑指南)。

    binlog 是 MySQL Server 层的日志,而不是存储引擎自带的日志,它记录了所有的 DDL 和 DML(不包含数据查询语句)语句,而且是以事件形式记录,还包含语句所执行的消耗的时间等,需要注意的是:

    • binlog 是一种逻辑日志,他里边所记录的是一条 SQL 语句的原始逻辑,例如给某一个字段 +1,注意这个区别于 redo log 的物理日志(在某个数据页上做了什么修改)。
    • binlog 文件写满后,会自动切换到下一个日志文件继续写,而不会覆盖以前的日志,这个也区别于 redo log,redo log 是循环写入的,即后面写入的可能会覆盖前面写入的。
    • 一般来说,我们在配置 binlog 的时候,可以指定 binlog 文件的有效期,这样在到期后,日志文件会自动删除,这样避免占用较多存储空间。

    根据 MySQL 官方文档的介绍,开启 binlog 之后,大概会有 1% 的性能损耗,不过这还是可以接受的,一般来说,binlog 有两个重要的使用场景:

    • MySQL 主从复制时:在主机上开启 binlog,主机将 binlog 同步给从机,从机通过 binlog 来同步数据,进而实现主机和从机的数据同步。
    • MySQL 数据恢复,通过使用 mysqlbinlog 工具再结合 binlog 文件,可以将数据恢复到过去的某一时刻。

    redo log

    前面我们说的 binlog 是 MySQL 自己提供的,在 MySQL 的 server 层,而 redo log 则不是 MySQL 提供的,是存储引擎 InnoDB 自己提供的。所以在 MySQL 中就存在两类日志 binlog 和 redo log,存在两类日志既有历史原因(InnoDB 最早不是 MySQL 官方存储引擎)也有技术原因,这个咱们以后再细聊。

    我们都知道,事务的四大特性里面有一个是持久性,即只要事务提交成功,那么对数据库做的修改就被永久保存下来了,写到磁盘中了,怎么做到的呢?其实我们很容易想到是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中,一旦写到磁盘中,就不怕数据丢失了。

    但是要是每次都这么搞,数据库就不知道慢到哪里去了!因为 Innodb 是以页为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,不仅效率低,也浪费资源。效率低是因为这些数据页在物理上并不连续,将数据页刷到磁盘会涉及到随机 IO。

    有鉴于此,MySQL 设计了 redo log,在 redo log 中只记录事务对数据页做了哪些修改。那有人说,写 redo log 不就是磁盘 IO 吗?而写数据到磁盘也是磁盘 IO,既然都是磁盘 IO,那干嘛不把直接把数据写到磁盘呢?还费这事!

    此言差矣。

    写 redo log 跟写数据有一个很大的差异,那就是 redo log 是顺序 IO,而写数据涉及到随机 IO,写数据需要寻址,找到对应的位置,然后更新/添加/删除,而写 redo log 则是在一个固定的位置循环写入,是顺序 IO,所以速度要高于写数据。

    redo log 本身又分为:

    • 日志缓冲(redo log buffer),该部分日志是易失性的。
    • 重做日志(redo log file),这是磁盘上的日志文件,该部分日志是持久的。

    MySQL 每执行一条 DML 语句,先将记录写入 redo log buffer,后续在某个时间点再一次性将多个操作记录写到 redo log file,这种先写日志再写磁盘的技术就是 MySQL 里经常说到的 WAL(Write-Ahead Logging) 技术(预写日志)。

    1.2 两阶段提交

    在 MySQL 中,两阶段提交的主角就是 binlog 和 redolog,我们来看一个两阶段提交的流程图:

    从上图中可以看出,在最后提交事务的时候,有 3 个步骤:

    1. 写入 redo log,处于 prepare 状态。
    2. 写 binlog。
    3. 修改 redo log 状态变为 commit。

    由于 redo log 的提交分为 preparecommit 两个阶段,所以称之为两阶段提交。

    2. 为什么需要两阶段提交

    如果没有两阶段提交,那么 binlog 和 redolog 的提交,无非就是两种形式:

    1. 先写 binlog 再写 redolog。
    2. 先写 redolog 再写 binlog。

    这两种情况我们分别来看。

    假设我们要向表中插入一条记录 R,如果是先写 binlog 再写 redolog,那么假设 binlog 写完后崩溃了,此时 redolog 还没写。那么重启恢复的时候就会出问题:binlog 中已经有 R 的记录了,当从机从主机同步数据的时候或者我们使用 binlog 恢复数据的时候,就会同步到 R 这条记录;但是 redolog 中没有关于 R 的记录,所以崩溃恢复之后,插入 R 记录的这个事务是无效的,即数据库中没有该行记录,这就造成了数据不一致。

    相反,假设我们要向表中插入一条记录 R,如果是先写 redolog 再写 binlog,那么假设 redolog 写完后崩溃了,此时 binlog 还没写。那么重启恢复的时候也会出问题:redolog 中已经有 R 的记录了,所以崩溃恢复之后,插入 R 记录的这个事务是有效的,通过该记录将数据恢复到数据库中;但是 binlog 中还没有关于 R 的记录,所以当从机从主机同步数据的时候或者我们使用 binlog 恢复数据的时候,就不会同步到 R 这条记录,这就造成了数据不一致。

    那么按照前面说的两阶段提交就能解决问题吗?

    我们来看如下三种情况:

    **情况一:**一阶段提交之后崩溃了,即写入 redo log,处于 prepare 状态 的时候崩溃了,此时:

    由于 binlog 还没写,redo log 处于 prepare 状态还没提交,所以崩溃恢复的时候,这个事务会回滚,此时 binlog 还没写,所以也不会传到备库。

    **情况二:**假设写完 binlog 之后崩溃了,此时:

    redolog 中的日志是不完整的,处于 prepare 状态,还没有提交,那么恢复的时候,首先检查 binlog 中的事务是否存在并且完整,如果存在且完整,则直接提交事务,如果不存在或者不完整,则回滚事务。

    **情况三:**假设 redolog 处于 commit 状态的时候崩溃了,那么重启后的处理方案同情况二。

    由此可见,两阶段提交能够确保数据的一致性。

    3. 小结

    好啦,今天和小伙伴们简单聊了一下 MySQL 中的两阶段提交,有问题欢迎留言讨论。

    展开全文
  • 分布式事务两阶段提交

    千次阅读 2022-02-20 15:18:20
    分布式两阶段提交
  • 分布式系统和分布式一致性问题 ...2PC(Two-Phase Commit 二阶段提交)   二阶段提交,是指将事务提交分成两个部分:准备阶段和提交阶段。事务的发起者称之为协调者,事务的执行者称为参与者。 阶段一:...
  • 分布式事务之两阶段提交

    千次阅读 2021-10-31 17:00:40
    阶段提交协议 两阶段提交协议把分布式事务分为两个阶段,一个是准备阶段,另一个是提交阶段; 准备阶段和提交阶段都是由事务管理器发起的; 我们可以将事务管理器称为协调者,将资源管理器称为参与者。 流程 ...
  • 简单谈谈MySQL的两阶段提交

    千次阅读 多人点赞 2021-12-19 21:16:59
    在讲解两阶段提交之前,需要对MySQL中的三种日志即binlog、redo log与undo log有一定的了解。 在这三种日志中,很多同学会把binlog与redo log混淆,下面使用一张表格来简单对比下两者的区别。 ...
  • MySQL的两阶段提交(数据一致性)

    千次阅读 2022-05-23 21:19:44
    MySQL的两阶段提交阶段提交过程为什么要写redo log,不写redo log的话,根本就不会出现“两阶段提交”的麻烦事啊?为什么要写两次redo log,写一次不行吗?在两阶段提交的情况下,是怎么实现崩溃恢复的呢? 在讲解...
  • 在分布式系统中,每一个机器...二阶段提交 二阶段提交将一个事务的处理过程分为投票和执行两个阶段,核心是对每个事务都采用先尝试后提交的处理方式 阶段一:提交事务请求 (1)事务询问 协调者向所有的参与者发送.
  • 浅谈两阶段提交和三阶段提交

    千次阅读 2020-03-07 20:30:23
    部分阐述三阶段提交的原理和优缺点。 第三部分阐述如何解决业务中最终一致性的问题。 一.两阶段提交阶段提交方法是用于分布式事务中用来完成事务操作的。 两阶段提交是一种思想,XA协议,TCC,Paxos...
  • 图片来源:pexels网站java4all原创,欢迎关注摘要:本文主要讲解分布式事务中二阶段提交协议(2pc)相关基础概念,原理及详细的执行过程。1.理论基础二阶段提交(...
  • 阶段提交不需要“协调者”角色,各结点之间不存在协调操作,因此其事务执行时间比两阶段提交要短,但是提交的“危险期”是每一个事务的实际提交时间,相比于两阶段提交,一阶段提交出现在“不一致”的概率就变大了...
  • 二阶段提交,三阶段提交,Paxos

    千次阅读 2017-02-08 10:17:50
    随着大型网站的各种高并发访问、海量数据处理等场景越来越多,...本文主要介绍关于分布式事务,二阶段提交和三阶段提交。  在分布式系统中,为了保证数据的高可用,通常,我们会将数据保留多个副本(replica),这些
  • 在分布式系统中,事务往往包含有多个参与者的活动,单个参与者上的活动是能够保证原子性的,而多个参与者之间原子性的保证则需要通过两阶段提交来实现,两阶段提交是分布式事务实现的关键。
  • 二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后...
  • 阶段提交的前提条件 两阶段提交的成立要基于以下假设: 该分布式系统中,存在一个节点作为协调者,其他节点作为参与者,且节点之间可以进行网络通信。 所有节点都采用预写式日志,且日志被写入后即被保存在可靠的...
  • mysql redolog binlog 之二阶段提交

    千次阅读 多人点赞 2020-03-20 10:08:41
    文章目录一:什么是redolog和binglog?:redolog和binlog可以相互替代或者只保留其一吗?...四:二阶段提交步骤五、redolog和binlog二阶段提交与redolog和binlog的顺序提交是否真的有区别?六...
  • mysql之两阶段提交

    千次阅读 2020-08-17 17:38:27
    什么是两阶段提交 当有数据修改时,会先将修改redo log cache和binlog cache然后在刷入到磁盘形成redo log file,当redo log file全都刷入到磁盘时(prepare 状态)和提交成功后才能将binlog cache刷入磁盘,当...
  • TCC和两阶段提交

    千次阅读 2019-09-15 20:00:10
    经常在网络上看见有人介绍TCC时,都提一句,”TCC是两阶段提交的一种”。其理由是TCC将业务逻辑分成try、confirm/cancel在两个不同的阶段中执行。其实这个说法,是不正确的。可能是因为既不太了解两阶段提交机制、也...
  • 分布式两阶段提交和三阶段提交

    万次阅读 多人点赞 2016-07-31 23:59:26
    随着大型网站的各种高并发访问、海量数据处理等场景越来越多,如何...本文主要介绍关于分布式事务,二阶段提交和三阶段提交。 在分布式系统中,为了保证数据的高可用,通常,我们会将数据保留多个副本(replica),这些
  • 阶段提交的缺点

    千次阅读 2019-02-15 17:10:07
    同步阻塞问题 单点故障 数据不一致
  •  因为事务需要实现ACID,即原子性、一致性、隔离性、持久性,所以需要采用一定的机制来... XA:XA协议,规定事务管理器和资源管理器接口,采用二阶段提交协议。 一阶段提交协议  一阶段提交协议相对简单,如
  • 因为2阶段提交存在单点故障、同步阻塞、网络脑裂等缺陷,所以在2阶段的基础上进行了改良,并提出了3阶段的概念。 2阶段和3阶段,事务提交有什么区别? 3阶段在2阶段的基础上做了2个改进点: 1.增加了超时机制,同时...
  • 阶段提交(Two-Phase Commit)

    千次阅读 2019-10-22 18:40:14
    阶段提交阶段提交是一种同步协议,是计算机网络尤其是在数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务处理过程中保持原子性和一致性而设计的一种算法。 两阶段提交的执行过程 在两阶段提交...
  • 二阶段提交与三阶段提交

    千次阅读 2019-06-05 21:34:20
    前面几篇博客中提到了CAP原理,以及CAP的几种组合,比如符合AP的有Gossip... 这篇文章就来介绍下二阶段提交和有所改进的三阶段提交二阶段提交(2PC) 为了使分布式系统架构下所有节点在进行事务提交时保持一致性...
  • 在分布式系统中,著有CAP理论,该理论由加州大学伯克利分校的Eric Brewer教授提出,该... 在分布式系统中数据往往存在多个副本,一致性描述的是这些副本中的数据在内容和组织上的一致。 可用性 可用性描述了系统对...
  • 文章目录问题协调者统一调度二阶段提交协议 问题 在分布式系统中,各个节点之间在物理上相互独立,通过网络进行沟通和协调。 在关系型数据库中,由于存在事务机制,可以保证每个独立节点上的数据操作满足 ACID。 ...
  • Flink两阶段提交

    万次阅读 多人点赞 2019-05-17 10:22:47
    文章目录两阶段提交阶段提交 何为EXACTLY_ONCE? EXACTLY_ONCE简称EOS,每条输入消息只会影响最终结果一次,注意这里是影响一次,而非处理一次,Flink一直宣称自己支持EOS,实际上主要是对于Flink应用内部来说的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 185,410
精华内容 74,164
热门标签
关键字:

二阶段提交存在问题