关于 2PC/3PC

giiiiiithub2024-07-24 15:280

关于 2PC 和 3PC

本质上这是一个分布式环境下关于原子性的协议。也就是 N 个参与者对同一事务:要么都成功要么都失败。


理解它的关键是以“投票”模型来思考,这里的“票”仅仅是:参与者表示自己是否可以完成本次事务。2PC 的两个阶段:

  1. 投票阶段: 协调者向所有参与者分发投票请求。 参与者各自将投票结果上报给协调者(等同于告知协调者:自己(可以/不可以)完成本次事务)

  2. 广播并执行投票意志阶段:协调者拿到所有参与者的投票后,开始向所有参与者广播投票结果,参与者根据投票结果来执行 commit or abort 。

问题的关键是:在投票阶段,有参与者的投票丢了怎么办?即:协调者还未收到所有参与者的投票就挂了,期间参与者也挂了。协调者恢复正常(或者重新选举)后,它还是得死等:挂掉的参与者重新恢复正常,再次问询它的投票是 yes or no ?得到回复后协调者才可以决定继续向前(commit)或者后退(abort)。它不能贸然进入第二阶段,告诉其他参与者投票结果是:abort or commit ,因为挂掉的参与者可能已经发出了 yes 的投票,也可能发出了 no 的投票,只不过他俩在次期间挂了,票丢在了半路上。

丢票后必须死等参与者恢复,这是 2PC 被称为阻塞协议的原因。


3PC 是通过引入临时状态寄存票选结果+超时,来解决阻塞问题的:

在投票阶段达成一致的 yes 之后,再插入一个阶段: 去中心化投票结果阶段 该阶段协调者向所有参与者分发一阶段的最终投票结果,参与者收到后会将其保存下来,并回复协调者:已保存。 这一阶段使得所有参与者手中都有了一阶段最终投票结果,而不再是仅仅在协调者手中。


所以:

无论在哪个阶段,挂掉的协调者恢复(或重新选举)后,都可以根据之前的投票结果继续做出决策,而不是阻塞:

  1. 未收到全体参与者在一阶段的投票结果,于是:等待,但不死等,超时后发起 abort 。
  2. 有参与者说 no ,于是:发起 abort 。
  3. 投票结果还未广播完成:于是:继续广播投票结果。
  4. 投票结果已广播完成:于是:保持沉默。

而挂掉的参与者恢复后会向协调者或者其他参与者询问:这个事务在一阶段投票的最终结果是 yes 还是 no ? (优先询问协调者,如果协调者挂了,就询问其他参与者。注意:协调者如果超时不能恢复也会被重新选举,所以参与者总是能得到回复)。

回复只有 3 个结果:

  1. yes 。于是 commit 事务。该回复如果是来自其他参与者,那原因就是:其他参与者至少有一个已经进入了第二、第三阶段。

  2. no 。 该回复如果来自其他参与者,那原因就是:有其他参与者已经收到协调者的 abort 请求。

  3. 未知。 原因是:协调者挂了,其他参与者都处于一阶段,(或者也都挂了)。这种情况下安静等待协调者恢复(或者重新选举)后,做出的决策。协调者恢复后,会向所有参与者继续分发一阶段投票结果。


所以 3PC 不在阻塞的关键就是:

引入中间阶段,在完成去中心化投票结果之前,可以放心 abort 。在去中心化投票结果完成之后,才去请求所有参与者执行投票意志,期间发生意外的的选手在恢复后可以问询其他选手投票结果。


另外: 以上像 保存票选结果 这类描述只是为了好理解,不涉及具体实现细节。

最新回复 (3)
  • laminux294月前
    引用2
    这玩意本质上是数学的概率问题,甚至可以扩展到 nPC 、RAIDn 、纠删码等等。

    相关的还有谷歌的数据 3 副本可以保证正常情况下不会丢数据。
  • pangdundun9964月前
    引用3
    感觉 2PC 、3PC 、TCC 这种引入协调中间节点的实现成本都太高,实际落地还是可靠事务消息会多点
  • giiiiiithub楼主4月前
    引用4
    简单总结就是:

    1. 在 **去中心化投票结果** 这一阶段完成之前, 假如协调者在一段时间内,不能确保所有参与者都拿到了自己的决策,就会按超时处理:向所有参与者分发 abort 的决策。又因为协调者总是可以被重新选举,所以即便这一 abort 决策在分发过程中协调者又挂了,那重新选举的的协调者,仍然可以以:超时不能确保所有参与者都拿到了自己的决策为由,继续分发 abort 决策。所以,abort 决策一定会被分发到所有参与者手中。

    2. 而一旦完成了 **去中心化投票结果** 这一阶段,总是能够保证:所有的节点都持有协调者的决策。无论谁挂了,恢复之后都可以询问任何其他节点,总是能得到回复(因为协调者可以被重新选举)
  • 回复请 登录 or 快速注册
返回