两阶段提交如何防止最后一秒失败?


75

我正在研究两阶段提交如何在分布式事务中工作。据我了解,在该阶段的最后部分,事务协调器会询问每个节点是否准备好提交。如果每个人都同意,那么它会告诉他们继续努力。

是什么防止以下故障?

  1. 所有节点均响应已准备好提交
  2. 事务协调器告诉他们“继续并提交”,但是其中一个节点崩溃,然后收到此消息
  3. 所有其他节点均成功提交,但现在分布式事务已损坏
  4. 据我了解,当崩溃的节点返回时,其事务将被回滚(因为它从未收到提交消息)

我假设每个节点都在运行一个普通的数据库,该数据库对分布式事务一无所知。我错过了什么?


2
您对普通数据库的假设是不正确的。任何资源(消息队列,数据库等)都支持分布式事务(通过支持事务协调器)或不支持。如果不这样做,那么将其包含在分布式事务中的做法可能会损害可靠性。
erickson

Erickson,如果您用您的评论折叠他人的答案,我会将其标记为正式答案。
吉利2009年

Answers:


43

不,不指示它们回滚,因为在原始发布者的场景中,某些节点已经提交。发生的事情是当崩溃的节点变为可用时,事务协调器告诉它再次提交。

因为该节点在“准备”阶段做出了积极响应,所以即使它从崩溃中恢复过来,也要求它能够“提交”。


我不明白崩溃的节点应该如何能够将事务重播到停止的位置。如果要在普通数据库之上安装分布式事务库,那么是什么阻止数据库在崩溃时回滚?
吉利

8
吉利:因为它承诺将能够在2PC的准备阶段。
托马斯,

3
@Gili崩溃的数据库不必重播事务。传统DB事务的工作方式是它们主动在事务日志中进行那些更改,只有当它能够获取必要的行/表/页锁时才会发生这种更改。本质上,在第一阶段之后,事务已经修改了数据库,但是其他查询只有将它们标记为已提交,才能看到这些更改。剩下要做的就是将它们标记为已落实。
AaronLS 2014年

26

总结大家的答案:

  1. 人们不能将普通数据库与分布式事务一起使用。数据库必须明确支持事务协调器。

  2. 不指示节点回滚,因为某些节点已经提交。发生的事情是当崩溃的节点返回时,事务协调器告诉它完成提交。


3
如果协调器在节点关闭时崩溃而节点在协调器仍然关闭时唤醒,会发生什么?节点然后做什么?
Aviad P.

3
我建议对此问题另开一个问题。我自己不知道答案,但是我猜想该节点在接受客户端连接之前会等待协调器返回。
吉利2009年

2
没有协调员,一切当然都会停下来。
Jaco Van Niekerk

21

否。第4点不正确。每个节点都在稳定的存储中记录了它能够提交或回滚该事务,因此即使在崩溃时也可以按照命令执行。当崩溃的节点恢复正常运行时,它必须意识到它的事务处于预提交状态,恢复所有相关的锁或其他控件,然后尝试联系协调器站点以收集事务的状态。

仅当崩溃的节点再也不会恢复时才会出现问题(然后其他一切都认为事务正常,或者当崩溃的节点恢复时就会发生)。


这不是假设数据库知道分布式事务吗?我以为您应该能够在不知道它的普通数据库之上安装分布式事务……
Gili

6
没有; DBMS必须了解其在2PC协议中的职责,并且主要职责是将事务保持为“通过/不通过”状态,直到协调员发出命令为止。那时您失去了(自主权)。Informix实施启发式回滚来处理已消失的系统。
乔纳森·莱夫勒

12

两阶段提交并不是万无一失的,只是设计为可以在99%的情况下使用。

“该协议假设每个节点上都有一个预写日志来稳定存储,没有节点永远崩溃,该预写日志中的数据在崩溃中永远不会丢失或损坏,并且任何两个节点都可以通信彼此之间。”

http://en.wikipedia.org/wiki/Two-phase_commit_protocol


即使满足了您提到的假设,我也看不到节点崩溃后应该如何重放事务(而不是回滚)。据我了解,数据库并不了解分布式事务。最重要的是。
吉利

@Gili:数据库必须知道分布式事务,才能正确支持2PC。如果您在顶部构建一些东西,那么您将没有可靠的2PC实现。
乔纳森·莱夫勒

这个说法不正确。在某些假设下2PC是100%正确的。对于这个问题,如果协调员指示,参与者必须持久存储来自预提交的数据,并且必须能够在重新启动后完成提交。如果失败,协调器还必须持久存储最终决定以回滚或提交并重试。同样,所有参与者都不能永远崩溃,他们必须最终重新启动并拥有持久存储的数据。如果满足这些要求,则2PC是100%正确的。如果不是,则可能不正确。
奥利夫,

7

有两阶段提交来解决问题的方法很多。它们几乎都作为Paxos三相提交算法的某些变体出现。在基于Paxos的Google上设计Chubby Lock服务的Mike Burrows说,在我看到的一次演讲中,有两种类型的分布式提交算法-“ Paxos和不正确的”。

当崩溃的节点重新唤醒时,可以做的一件事是说“我从未听说过该事务,是否应该提交?” 交给协调员,协调员将告诉投票结果。

请记住,这是一个更普遍的问题的示例:崩溃的节点在恢复之前可能会丢失许多事务。因此,非常重要的是,恢复后应在可用之前与协调器或另一个副本进行对话。如果节点本身无法确定它是否已崩溃,那么事情将涉及更多但仍然易于处理。

如果将仲裁系统用于数据库读取,则不一致将被掩盖(并使数据库本身知道)。


节点重新唤醒后如何重播事务?据我了解,普通数据库总是在崩溃时回滚,并且它们不了解分布式事务(您可以在它们之上安装一些库)。因此,我看不到如何进行这项工作。
吉利
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.