Database 两阶段提交

Database 两阶段提交,database,distributed-transactions,Database,Distributed Transactions,我相信大多数人都知道什么是2PC两阶段提交协议,以及如何在Java或大多数现代语言中使用它。基本上,当您有2个或更多的数据库时,它用于确保事务同步 假设我有两个数据库A和B在两个不同的位置使用2PC。在A和B准备提交事务之前,两个DBs都将向事务管理器报告它们准备提交。因此,当事务管理器被确认时,它将向a和B发送一个信号,告诉他们继续 我的问题是:假设A收到信号并提交了交易。一旦一切都完成了,B也要这么做,但有人拔下了电源线,导致整个服务器关闭。当B重新联机时,B将做什么?B是怎么做到的 请记住

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

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

我的问题是:假设A收到信号并提交了交易。一旦一切都完成了,B也要这么做,但有人拔下了电源线,导致整个服务器关闭。当B重新联机时,B将做什么?B是怎么做到的

请记住,A已提交但B未提交,我们正在使用2PC,因此2PC的设计停止工作,不是吗?

关于两阶段提交

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

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

当B重新联机时,事务管理器将再次轮询B,并要求其提交事务。如果B已经提交了事务,它会将事务报告为已提交。如果B还没有提交事务,那么它将提交,因为它已经持久化了事务,因此仍然能够提交事务

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

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

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

应用程序仍然必须能够从错误中恢复,但是事务不能在应用程序不知道不一致状态的情况下以静默方式失败

语义学

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

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

如果TM在第1阶段下降,则客户端将阻塞,直到 TM将返回,除非它超时或由于以下原因收到错误: 网络连接中断。在这种情况下,客户会意识到 错误,可以重试或启动中止本身

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

资源管理器中的提交后数据丢失事件不由事务管理器处理,而是RMs恢复能力的一个功能

两阶段提交不能保证容错性(请参阅解决容错性的协议示例),但它可以保证分布式事务的部分故障不会被忽略

请注意,这种失败也可能会丢失以前提交的事务中的数据。两阶段提交不能保证资源管理器不会丢失或损坏数据,也不能保证灾难恢复过程不会出错。
我认为三阶段提交是一种更好的方法。不幸的是,我还没有找到任何人实现这样的技术

以下是上述条款的基本部分:

2PC的根本困难在于,一旦 协调人已完成提交,并已将其传递给某些复制副本,这些复制副本立即执行commit语句,而无需检查是否每个其他复制副本都收到了该消息。然后,如果提交的复制副本与协调器一起崩溃,系统无法知道事务的结果是什么,因为只有协调器和获得消息的复制副本可以确定。由于事务可能已经在崩溃的复制副本上提交,因此协议不能悲观地中止,因为事务可能具有无法撤消的副作用。类似地,协议不能乐观地强制事务提交,因为最初的投票可能是中止

通过在2PC中添加一个额外的阶段来解决这个问题,毫不奇怪,它为我们提供了一个三阶段提交协议。这个想法很简单。我们将2PC的第二阶段——“提交”分为两个子阶段。第一个阶段是“准备提交”阶段。协调员在第一阶段收到一致的“是”票后,将此消息发送给所有副本。收到此消息后,复制副本会进入一种状态,在这种状态下,它们可以提交事务(通过采取必要的锁定等方式),但关键的是,它们不会执行任何以后无法撤消的工作。然后,他们回复协调员,告知其已收到“准备提交”消息

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

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

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


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

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

最好将链接文章的关键部分放在答案中,这样,如果链接发生更改,信息不会丢失。您应该在系统中真正使用Raft或Paxos而不是3PC,这个答案做出了一个危险的假设,我不确定你的意思。如果在第一阶段出现网络中断,TM
由于致命错误,将无法连接到其中一个RMs并中止事务,最终通知所有RMs在恢复联机时中止。在第二阶段中,它将继续轮询RM,直到网络恢复,此时它将发出确认提交。同样,2PC并不保证提交,它只是保证在应用程序不知道的情况下事务不会失败。如果TM在收到所有提交投票后,但在发送最终提交/中止之前崩溃,该怎么办?然后每个人都拿着锁,等待投票。您不能超时,一些节点可能会提交,而其他节点则超时并中止。如果您有一个同步可靠的网络,并且没有节点崩溃,并且您有实时操作系统,因此您可以保证在有限的时间内取得进展,那么2PC就可以工作。通常,我们没有这些属性。不要混淆2PC语义和容错。在第二阶段收到所有提交的确认之前,TM仍将事务标记为未提交。当它返回时,它将轮询所有资源管理器并要求他们提交,他们将报告事务已提交。请记住,RMs必须能够保证提交。在第二阶段报告成功提交后,或者在第二阶段之后的任何时候,2PC都不会对RM的灾难性故障做任何处理。下面是一篇关于称为Paxos的三阶段提交协议的论文,它确实解决了容错问题。但是wiki说,队列向协调器发送协议消息后,它将阻塞,直到收到提交或回滚。我相信这意味着B在发送协议消息后会阻塞,即使消息从未到达TM,或者提交/回滚消息在返回的过程中丢失,B根本不知道也不关心。但B不会永远阻塞。因为在假设没有节点永远崩溃,并且任何两个节点都可以相互通信的情况下,B最终将获得提交/回滚消息,从而完成整个过程。另一个回复得到的评论是,该回复做出了一个危险的假设,即网络是可靠的。这是一个危险的假设,是的。但我认为维基页面中的两个假设并不认为网络是可靠的。它只是说任何两个节点都可以相互通信,这意味着,据我所知,并非所有的消息都会在网络上丢失。然后,通过某种超时和重试机制,协议消息和提交/回滚消息最终将到达目的地,算法可能会继续。如果B感到厌烦并决定中止事务,则TM将在下次重新联机时要求其提交,B将为TxID报告错误。事务仍将失败,但不会默默失败;TM仍然会注意到B.2PC上中止的事务。2PC不是关于容错,而是关于确保分布式事务以原子方式提交,并且在分布式事务中的错误发生时会被发现。