【问题标题】:Two phase commit两阶段提交
【发布时间】:2011-11-15 09:44:16
【问题描述】:

我相信大多数人都知道什么是 2PC(两阶段提交协议)以及如何在 Java 或大多数现代语言中使用它。基本上,当您有 2 个或更多 DB 时,它用于确保事务同步。

假设我有两个 DB(A 和 B)在两个不同的位置使用 2PC。在 A 和 B 准备好提交事务之前,两个 DB 都会向事务管理器报告它们已准备好提交。因此,当事务管理器被确认时,它会向 A 和 B 发送一个信号,告诉他们继续。

这是我的问题:假设 A 收到信号并提交了交易。一切搞定后,B也准备照做,但有人拔掉了电源线,导致整个服务器关机。当 B 重新上线时,B 会做什么? B是怎么做到的?

请记住,A 已提交但 B 未提交,我们使用的是 2PC(所以,2PC 的设计停止工作了,不是吗?)

【问题讨论】:

    标签: database distributed-transactions


    【解决方案1】:

    关于两阶段提交

    两阶段提交并不能保证分布式事务不会失败,但可以保证它不会在 TM 不知道的情况下静默失败。

    为了让 B 报告事务已准备好提交,B 必须将事务保存在持久存储中(即 B 必须能够保证事务在所有情况下都可以提交)。在这种情况下,B 已将事务持久化,但事务管理器尚未收到 B 确认 B 已完成提交的消息。

    当 B 重新上线时,事务管理器将再次轮询 B,并要求它提交事务。如果 B 已经提交了事务,它将报告事务已提交。如果 B 还没有提交事务,它将提交,因为它已经持久化了它,因此仍然可以提交事务。

    为了让 B 在这种情况下发生故障,它必须经历一次丢失数据或日志条目的灾难性故障。事务管理器仍然会知道 B 没有报告成功提交。1

    在实践中,如果 B 不能再提交事务,则意味着将 B 带出的灾难导致数据丢失,当 TM 要求它提交一个不是它的 TxID 时,B 会报告错误知道或不认为处于可提交状态。

    因此,两阶段提交并不能防止灾难性故障的发生,但它确实可以防止故障被忽视。在这种情况下,如果 B 无法提交,事务管理器将向应用程序报告错误。

    应用程序仍然必须能够从错误中恢复,但事务不能在不让应用程序意识到不一致状态的情况下静默失败。

    语义

    • 如果资源管理器或网络在阶段 1 出现故障,则 事务管理器将检测到致命错误(无法连接到 资源管理器)并将子事务标记为失败。当。。。的时候 网络恢复,它将中止所有 参与的资源经理。

    • 如果资源管理器或网络在第 2 阶段出现故障,则 事务管理器将继续轮询资源管理器,直到 它回来了。当它重新连接到资源管理器时 它会告诉 RM 提交事务。如果 RM 返回一个 TM 会意识到“未知 TxID”的错误 RM 中存在数据丢失问题。

    • 如果 TM 在第 1 阶段出现故障,则客户端将阻塞,直到 TM 会恢复,除非它超时或收到错误,因为 网络连接断开。在这种情况下,客户会意识到 错误,可以重试或自行启动中止。

    • 如果 TM 在第 2 阶段出现故障,那么它将阻止客户端,直到 TM 回来了。它已经将交易报告为 可提交且不应向客户端显示致命错误, 尽管它可能会阻塞直到 TM 恢复。 TM 仍将 使事务处于未提交状态并将轮询 RM 当它恢复时提交。

    资源管理器中的提交后数据丢失事件不由事务管理器处理,并且是 RM 弹性的函数。

    两阶段提交不保证容错 - 请参阅 Paxos 了解解决容错的协议示例 - 但它确实保证分布式事务的部分故障不会被忽视。

    1. 请注意,这种故障也可能会丢失以前提交的事务中的数据。两阶段提交并不能保证资源管理器不会丢失或损坏数据,或者 DR 过程不会出错。

    【讨论】:

    • 这个答案做出了一个危险的假设,即The Network is Reliable
    • 我不确定你在说什么。如果在第一阶段发生网络中断,TM 将无法连接到其中一个 RM 并由于致命错误而中止事务,最终告诉所有 RM 在它们重新联机时中止。在第二阶段,它将继续轮询 RM,直到网络恢复正常,此时它将发出确认提交。同样,2PC 不保证提交,它只是保证事务不会在应用程序不知道的情况下失败。
    • 如果 TM 在收到所有提交投票后但在发送最终提交/中止之前崩溃怎么办?然后每个人都拿着锁,等待投票。而且你不能超时,一些节点可能会提交,而其他节点可能会超时并中止。如果你有一个同步可靠的网络,并且没有节点崩溃,并且你有实时操作系统,所以你可以保证在有限的时间内取得进展,那么 2PC 就可以工作。通常,我们没有这些属性。
    • 不要将 2PC 语义与容错混淆。 TM 仍会将事务标记为未提交,直到它在第二阶段收到所有提交的确认。当它恢复时,它将轮询所有资源管理器并要求他们提交,他们将报告事务已提交。请记住,RM 必须能够保证提交。 2PC 在报告第二阶段成功提交后(或之后的任何时间)不会对 RM 的灾难性故障采取任何措施。
    • 这是一篇关于名为 Paxos 的三阶段提交协议的论文,它确实解决了容错问题。 research.microsoft.com/pubs/64636/tr-2003-96.pdf
    【解决方案2】:

    我相信三阶段提交是一种更好的方法。不幸的是,我还没有找到任何人实施这种技术。

    http://the-paper-trail.org/blog/consensus-protocols-three-phase-commit/

    以下是上述文章的基本部分:

    2PC 的根本困难在于,一旦协调者做出提交决定并与某些副本进行通信,这些副本就会继续执行提交语句,而无需检查是否所有其他副本都得到了消息。然后,如果提交的副本与协调者一起崩溃,则系统无法告知事务的结果是什么(因为只有协调者和收到消息的副本才能确定)。由于事务可能已经在崩溃的副本上提交,因此协议不能悲观地中止——因为事务可能具有无法撤消的副作用。同样,协议不能乐观地强制事务提交,因为最初的投票可能是中止。

    这个问题——主要是——通过向 2PC 添加一个额外的阶段来规避,不出所料地为我们提供了一个三阶段提交协议。这个想法很简单。我们将 2PC 的第二阶段——“提交”——分成两个子阶段。第一个是“准备提交”阶段。当协调者在第一阶段收到一致的“是”票时,它会将此消息发送给所有副本。收到此消息后,副本进入一种能够提交事务的状态——通过获取必要的锁等——但至关重要的是,它们不会做任何他们以后无法撤消的工作。然后他们回复协调员,告诉它“准备提交”消息已收到。

    此阶段的目的是将投票结果传达给每个副本,以便无论哪个副本死亡,都可以恢复协议的状态。

    协议的最后阶段与 2PC 中最初的“提交或中止”阶段几乎完全相同。如果协调者收到来自所有副本的“准备提交”消息的传递确认,则可以安全地继续提交事务。但是,如果未确认交付,则协调者无法保证协议状态在崩溃时会恢复(如果您要容忍固定数量的失败 f,则协调者可以在收到 f+1 后继续确认)。在这种情况下,协调者将中止事务。

    如果协调器在任何时候崩溃,恢复节点可以接管事务并从任何剩余的副本中查询状态。如果已提交事务的副本崩溃,我们知道每个其他副本都收到了“准备提交”消息(否则协调器不会移动到提交阶段),因此恢复节点将是能够确定事务能够被提交,并安全地引导协议完成。如果任何副本向恢复节点报告它尚未收到“准备提交”,则恢复节点将知道该事务尚未在任何副本上提交,因此将能够悲观地中止或重新运行协议从一开始。

    那么 3PC 能解决我们所有的问题吗?不完全是,但它很接近。在网络分区的情况下,轮子会脱落——想象所有收到“准备提交”的副本都在分区的一侧,而那些没有收到的副本在另一侧。然后两个分区将继续与分别提交或中止事务的恢复节点,并且当网络合并时系统将具有不一致的状态。所以 3PC 和 2PC 一样有潜在的不安全运行,但总是会取得进展,因此满足其活性特性。 3PC 不会阻塞单节点故障这一事实使其对高可用性比低延迟更重要的服务更具吸引力。

    【讨论】:

    • 最好将链接文章的基本部分放在答案中,这样,如果链接更改,信息不会丢失。
    • 你应该在你的系统中真正使用 Raft 或 Paxos 而不是 3PC,以获得实际的正确性。
    【解决方案3】:

    您的场景并不是唯一一个尽管付出了所有努力最终还是会出错的场景。假设 A 和 B 都向 TM 报告了“准备提交”,然后有人拔掉了 TM 和 B 之间的界限。B 正在等待 TM 的允许(或禁止),但它肯定赢了不要一直等待直到 TM 重新连接(由于显而易见的原因,它自己在事务中涉及的资源必须在整个等待时间内保持锁定/不可访问)。因此,当 B 为自己的口味等待太久时,它将采取所谓的“启发式决策”。也就是说,它将决定独立于 TM 提交或回滚,基于,嗯,我真的不知道是什么,但这并不重要。显然,任何此类启发式决策都可能偏离 TM 做出的实际提交决策。

    【讨论】:

    • 但是 wiki 说“在群组向协调者发送协议消息后,它将阻塞,直到收到提交或回滚”。我相信这意味着 B 在发送协议消息后会阻塞,即使消息永远不会到达 TM 或者提交/回滚消息在 B 根本不知道也不关心的返回途中丢失。
    • 但是 B 不会永远阻塞。因为在“没有节点永远崩溃”和“任意两个节点可以相互通信”的假设下,B最终会得到提交/回滚消息,从而完成整个过程。 en.wikipedia.org/wiki/Two-phase_commit_protocol
    • 另一个回复得到了评论说回复“做出了危险的假设网络是可靠的”。
    • 这是一个危险的假设,是的。但我认为 wiki 页面中的两个假设并不假设网络是可靠的。它只是说任何两个节点“可以”相互通信,这意味着,据我了解,并非所有消息都在网络上丢失。然后通过一些超时和重试机制,协议消息和提交/回滚消息最终将到达目的地,算法可能会继续。
    • 如果 B 感到无聊并决定中止事务,则 TM 将在下次重新联机时要求它提交,并且 B 将报告 TxID 错误。事务仍然会失败,但不会静默失败; TM 仍会知道 B 上的中止事务。2PC 不是关于容错,而是关于确保分布式事务以原子方式提交,并且分布式事务中的错误在发生时被拾取。
    猜你喜欢
    • 2011-11-24
    • 2013-05-21
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-16
    • 1970-01-01
    相关资源
    最近更新 更多