我相信大多数人都知道2PC(两阶段提交协议)是什么以及如何在Java或大多数现代语言中使用它。基本上,当您有2个或更多DB时,它用于确保事务处于同步状态。
假设我在两个不同的位置使用2PC有两个DB(A和B)。在A和B准备提交事务之前,两个DB都将向事务管理器报告,说它们已准备好提交。因此,当事务管理器得到确认时,它会向A和B发送一个信号,告诉他们继续。
这是我的问题:让我们说A收到了信号并提交了交易。一切都完成后,B即将做同样的事情,但有人拔掉电源线,导致整个服务器关闭。当B重新上线时,B会做什么? B怎么做呢?
请记住,A已提交,但B未提交,我们正在使用2PC(因此,2PC的设计停止工作,不是吗?)
答案 0 :(得分:58)
关于两阶段提交
两阶段提交并不能保证分布式事务不会失败,但它确保它不会在TM没有意识到的情况下以静默方式失败。
为了使B报告事务准备好提交,B必须在持久存储中具有事务(即B必须能够保证事务可以在所有情况下提交)。在这种情况下,B持有交易,但交易经理尚未收到B的确认B已完成提交的消息。
当B重新联机并要求其提交交易时,事务管理器将再次轮询B.如果B已经提交了事务,它将报告事务为已提交。如果B尚未提交事务,则它将继续提交,因为它已经持久化,因此仍然可以提交事务。
为了使B在这种情况下失败,它将不得不经历失去数据或日志条目的灾难性故障。事务管理员仍然知道B没有报告成功提交。 1
实际上,如果B不再提交事务,则意味着B out的灾难导致数据丢失,当TM要求提交TxID时,B会报告错误意识到或者没有想到处于可以承诺的状态。
因此,两阶段提交不会阻止发生灾难性故障,但它确实可以防止故障被忽视。在这种情况下,如果B无法提交,事务管理器将向应用程序报告错误。
应用程序仍然必须能够从错误中恢复,但是如果没有让应用程序知道不一致的状态,事务就不能无声地失败。
<强>语义强>
如果资源管理器或网络在阶段1中发生故障,那么 事务管理器将检测到致命错误(无法连接到 资源管理器)并将子事务标记为失败。当。。。的时候 网络重新启动它会中止所有的交易 参与的资源管理者。
如果资源管理器或网络在第2阶段出现故障,那么 事务管理器将继续轮询资源管理器,直到 它回来了。当它重新连接回资源管理器时 它会告诉RM提交交易。如果RM返回 沿着'未知TxID'的错误,TM会意识到这一点 RM中存在数据丢失问题。
如果TM在阶段1中关闭,那么客户端将阻塞直到 TM会重新启动,除非它超时或因错误而收到错误 破碎的网络连接。在这种情况下,客户了解 错误,可以重新尝试或启动中止本身。
如果TM在阶段2中关闭,那么它将阻止客户端直到 TM回来了。它已将此交易报告为 应该向客户提交可承诺且不致命的错误, 虽然它可能会阻止,直到TM恢复。 TM仍然会 使交易处于未提交状态并将轮询RM 在它重新启动时提交。
资源管理器中的提交后数据丢失事件不由事务管理器处理,并且是RM的弹性的函数。
两阶段提交不保证容错 - 请参阅Paxos以获取解决容错问题的协议示例 - 但它确实可以保证分布式事务的部分失败不会被忽视。
答案 1 :(得分:3)
尽管付出了很多努力,但您的情景并不是唯一可能最终出错的情景。假设A和B都报告“准备提交”到TM,然后有人拔掉TM之间的线路,比如说B. B正在等待TM的反超(或禁止),但它肯定赢了在TM重新连接之前一直等待(由于显而易见的原因,在整个等待时间内,事务中涉及的资源必须保持锁定/不可访问)。因此,当B为了自己的品味而等待太久时,它将采取所谓的“启发式决策”。也就是说,它将决定独立于TM提交或回滚,基于,我真的不知道什么,但这并不重要。显而易见的是,任何此类启发式决策都可能偏离TM所做出的实际提交决策。
答案 2 :(得分:2)
我相信三阶段提交是一种更好的方法。不幸的是,我没有找到任何实施这种技术的人。
http://the-paper-trail.org/blog/consensus-protocols-three-phase-commit/
以上是上述文章的基本部分:
2PC的根本困难在于,一旦决策提交由协调员做出并传达给一些副本,副本就会直接进行并执行提交语句而不检查是否每个其他副本都有消息。然后,如果提交的副本与协调器一起崩溃,则系统无法告知事务的结果是什么(因为只有协调器和获得消息的副本才能确定)。由于事务可能已经在崩溃的副本中提交,因此协议不能悲观地中止 - 因为事务可能具有无法撤消的副作用。同样,协议也不能乐观地强制提交事务,因为原始投票可能已经中止。
这个问题 - 主要是 - 通过向2PC添加额外阶段来规避,毫不奇怪地给我们提供了三阶段提交协议。这个想法非常简单。我们将2PC的第二阶段 - '提交' - 分为两个子阶段。第一个是“准备提交”阶段。当协调员在第一阶段收到一致的“是”投票时,协调员会将此消息发送给所有副本。收到此消息后,副本将进入一个可以提交事务的状态 - 通过采取必要的锁等等 - 但最重要的是不要做任何他们以后无法撤消的工作。然后他们回复协调员,告诉他们收到了“准备提交”的消息。
此阶段的目的是将投票结果传达给每个副本,以便无论哪个副本死亡,都可以恢复协议的状态。
协议的最后阶段与2PC中的原始“提交或中止”阶段几乎完全相同。如果协调员收到来自所有副本的“准备提交”消息的确认,则可以安全地继续提交事务。但是,如果未确认交付,协调员无法保证协议状态在崩溃时将被恢复(如果您容忍固定数量的失败,协调员可以在收到f + 1后继续进行)确认)。在这种情况下,协调员将中止交易。
如果协调员在任何时候崩溃,恢复节点可以接管事务并从任何剩余的副本中查询状态。如果已提交事务的副本已崩溃,我们知道每个其他副本都收到“准备提交”消息(否则协调器不会移动到提交阶段),因此恢复节点将是能够确定事务是否能够被提交,并安全地将协议提交给它。如果任何副本向恢复节点报告它尚未收到“准备提交”,则恢复节点将知道该事务尚未在任何副本上提交,因此将能够悲观地中止或重新运行协议从一开始。
3PC也解决了我们所有的问题吗?不完全,但它接近。在网络分区的情况下,轮子相当脱落 - 想象所有收到'准备提交'的副本都在分区的一侧,而那些没有的副本在另一侧。然后,两个分区将继续分别提交或中止事务的恢复节点,并且当网络合并时,系统将具有不一致的状态。所以3PC有可能不安全的运行,2PC也是如此,但总会取得进展,因此满足其活性属性。 3PC不会阻止单节点故障的事实使得它对于高可用性比低延迟更重要的服务更具吸引力。