文章目录
三阶段提交协议(Three-Phase Commit, 3PC)是分布式系统中用于保证跨多个节点的数据一致性的算法。它是在两阶段提交(2PC)的基础上发展起来的,旨在解决2PC的一些局限性,如协调者单点故障和阻塞问题。3PC通过引入额外的准备阶段来尝试减少阻塞时间,并且允许参与者在某些情况下自主决定是否继续事务,从而提高了系统的可用性和灵活性。
3PC旨在保持满足2PC的强一致性,又不存在同步阻塞和不一致的问题。
一、核心实现原理
优化
- 将prepare分为canCommit和preCommit:
为了提高2PC的性能,3PC将2PC的prepare阶段(第一阶段)分成CanCommit(询问阶段)、PreCommit(预提交阶段)。
这样改动后,3PC的执行过程为:询问——>锁定事务阶段(预提交)——>提交事务阶段。这样设计是为了减少事务资源锁定的范围,如果在集群中存在个别不具备处理事务能力的参与者,可以提前中断事务,而不像2PC一样,从一开始就锁定所有参与者的事务资源。
- 增加超时重传机制:
为了解决同步阻塞问题,3PC增加了超时机制,解决了当协调者宕机时,参与者无法释放事物资源的问题。这里增加的超时机制主要体现在参与者等待协调者的请求,超时后会执行默认的commit/abort指令。
三个阶段
1.CanCommit询问阶段
在三阶段提交协议(3PC)中,CanCommit 阶段是事务处理流程的第一步。这个阶段的主要目的是确保所有参与者都能够执行即将进行的事务,而不会遇到任何不可恢复的错误或资源冲突。
-
协调者发起请求:协调者(Coordinator)向所有参与者(Participants)发送
CanCommit
请求(包含了全局事务的内容),询问它们是否能够准备执行该事务。此阶段不涉及实际的数据修改,只是确认每个参与者是否有足够的资源和条件来完成事务。 -
参与者响应:每个参与者收到
CanCommit
请求后,会检查自身状态、资源可用性和其他可能影响事务成功的因素。如果一切正常,参与者将锁定必要的资源(当前阶段并不锁定),并回复协调者一个肯定的回答(通常是Yes
或OK
),表示它准备好参与此次事务;如果有任何问题使得参与者无法保证成功完成事务,则回复否定的回答(如No
或Abort
)。 -
协调者收集反馈并决策:协调者等待所有参与者的回应。一旦所有参与者都回复了肯定的答案,协调者就会进入下一个阶段——PreCommit。
-
超时机制:为了避免某个参与者长时间无响应而导致整个系统阻塞,协调者会在发出
CanCommit
请求时设置一个合理的超时期限。如果在超时之前没有收到某个参与者的回应,协调者可以假设该参与者已经失败,中断全局事务,并向所有参与者发送Abort命令;其他参与者则自行更新分支事务状态为中断。
2.PreCommit预提交阶段
在三阶段提交协议(3PC)中,PreCommit 阶段是事务处理流程的第二个关键步骤。这一阶段紧跟在 CanCommit 阶段之后,在所有参与者都确认能够执行事务的前提下进行。PreCommit 的主要目的是让每个参与者准备好实际执行事务,但还不真正提交,以便在最后阶段做出最终决定之前确保所有参与者已经准备好了一致的动作。
-
协调者发送 PreCommit 请求:一旦所有参与者在 CanCommit 阶段都回复了肯定的回答(即它们都能够执行该事务),协调者将向所有参与者发送
PreCommit
请求,指示它们准备执行事务。此请求通常包含事务的详细信息和一个唯一的事务标识符。 -
参与者准备事务:收到
PreCommit
请求后,每个参与者将执行以下操作:- 准备资源:根据事务的要求准备必要的资源。例如,数据库中的参与者可能会锁定行或表以防止其他事务对其进行修改。
- 写入预提交日志:为了确保即使在系统崩溃后也能够恢复到一致状态,参与者会记录下预提交的日志条目。这些日志条目包含了足够的信息,使得参与者可以在后续阶段根据需要回滚或提交事务。
- 持久化状态:确保上述准备工作是持久化的,也就是说,即使发生故障重启后也能保证这些状态不会丢失。
-
参与者响应:完成准备工作后,参与者向协调者发送确认消息(如
Prepared
),表明它已经准备好提交事务。如果在这个过程中遇到了问题,比如资源准备失败,则参与者会发送错误或拒绝的消息给协调者,并开始回滚事务。 -
协调者收集反馈并决策:协调者等待所有参与者的
Prepared
消息。如果所有参与者都成功准备好了,协调者将继续进入最后一个阶段——DoCommit。然而,如果有任何一个参与者未能准备好或者超时未响应,协调者可以选择取消整个事务,并通知所有参与者进行回滚。 -
容错能力增强:通过引入 PreCommit 阶段,3PC 协议增强了系统的容错能力。即使协调者在 DoCommit 阶段之前出现故障,参与者也可以基于其预提交的状态自主决定继续提交或回滚事务,从而减少了对协调者的依赖。
系统的容错能力(Fault Tolerance)是指一个系统在遇到硬件故障、软件错误或操作失误等异常情况时,仍然能够继续提供预期功能的能力。换句话说,它衡量的是系统在部分组件失效的情况下保持正常运行和服务连续性的能力。一个具有高容错能力的系统能够在不中断服务的前提下处理和恢复错误。
3.DoCommit提交阶段
在三阶段提交协议(3PC)中,DoCommit 阶段是事务处理流程的最后一个关键步骤。此阶段是在所有参与者都成功通过了前两个阶段——CanCommit 和 PreCommit 之后进行的。DoCommit 的主要目的是让所有参与者正式提交它们之前已经准备好的事务,确保整个分布式系统的一致性。
-
协调者发送 DoCommit 请求:一旦协调者从所有参与者那里收到了肯定的
Prepared
消息,表明每个参与者都已经成功准备好了事务,协调者将向所有参与者发送DoCommit
请求,指示它们正式提交事务。这个请求通常包含事务的唯一标识符,以确保参与者能够正确识别和匹配相应的事务。 -
参与者执行提交:收到
DoCommit
请求后,每个参与者将执行以下操作:- 实际提交事务:根据预提交阶段所做的准备工作,参与者现在可以安全地执行实际的数据修改,并将这些更改持久化到数据库或存储系统中。
- 记录提交日志:为了确保即使在系统崩溃后也能恢复到一致状态,参与者会在本地记录下提交的日志条目。这一步骤确保了即使后续发生了故障,参与者也可以在恢复时确认事务已经被提交。
-
参与者响应:完成提交后,参与者向协调者发送确认消息(如
Committed
),表明它已经成功提交了事务。如果在这个过程中遇到了问题(例如,提交失败),参与者会尝试回滚事务,并向协调者报告错误。 -
协调者收集反馈并结束事务:协调者等待所有参与者的
Committed
确认消息。一旦所有参与者都成功提交了事务,协调者就可以宣布事务成功完成,并通知所有相关方。如果有任何一个参与者未能成功提交,则需要采取适当的措施来解决这个问题,可能包括回滚其他已经提交的参与者。 -
幂等性和超时机制:如同之前的阶段一样,DoCommit 阶段的操作也是幂等的,这意味着即使相同的
DoCommit
消息被多次接收,其结果也是一样的,避免了不必要的重复提交。此外,超时机制也被应用于这个阶段,以防止某个参与者长时间无响应而导致整个系统阻塞。 -
容错能力:通过引入 DoCommit 阶段,3PC 协议进一步增强了系统的容错能力。即使协调者在此阶段出现故障,参与者可以根据预提交的状态自主决定继续提交事务,从而减少了对协调者的依赖。如果一个参与者在网络分区或其他异常情况下无法接收到
DoCommit
请求,它可以在超时后基于预提交日志做出合理的决策,比如尝试提交或等待更长的时间再做决定。
二、故障恢复
1.协调者发生故障
-
当协调者在全局事务canCommit阶段发生故障,所有参与者在等待协调者的请求超时后,会默认执行命令中断事务。
-
当协调者在全局事务preCommit阶段发生故障,此时需要判断所有参与者是否都完成了此阶段的工作,如果是则所有参与者自行提交分支事务;如果否,一部分参与者自行提交已完成的分支事务,另一部分参与者自行中断未完成的分支事务。这种情况下,容易导致数据不一致的问题
-
当协调者在全局事务doCommit阶段发生故障时,所有参与者等待协调者的请求超时后默认执行提交命令来提交分支事务。
心跳机制解决数据不一致问题
为了解决preCommit阶段协调者故障导致的数据不一致的问题,需要引入心跳机制,让参与者能够察觉到协调者的运行状态。当参与者监察到协调者发生异常且自己处于第二阶段时,应该临时停用超时机制,等待新的协调者的下一步请求。此外,这个约束需要满足心跳超时远小于等待协调者的超时,这样才能在等待协调者超时之前察觉到协调者的异常。
2.部分参与者发生故障
- 如果参与者是在全局事务的canCommit阶段发生故障,协调者等待该参与者的请求超时后将中断全局事务,该故障参与者在恢复过来之后,自行中断分支事务。
- 如果参与者是在全局事务的preCommit阶段发生故障:
- 该参与者已经完成二阶段工作,但并未向协调者反馈此阶段的执行结果,那么,协调者需要发送中断事务命令给所有的参与者;如果,该故障协调者向协调者反馈了此阶段的执行结果,那么协调者根据所有参与者的反馈来决定发送提交/中断事务的命令。
- 如果该故障参与者未完成了第二阶段的工作,那么协调者在等待故障参与者的请求超时后中断全局事务,该故障参与者在恢复过来之后,自行中断分支事务。
- 如果参与者是在全局事务的doCommit阶段发生故障,那么故障参与者在恢复后向协调者询问全局事务状态,并根据当前的全局事务状态来决定下一步的工作。
三、优缺点分析
优点
三阶段提交协议是为了解决二阶段提交协议同步阻塞问题而诞生的,所以它具有以下优点:
-
减少阻塞时间:通过将2PC的prepare阶段拆分为CanCommit和PreCommit两个阶段,减少了资源锁定的时间。如果在CanCommit阶段发现有参与者无法执行事务,可以在不锁定资源的情况下提前中断事务。
-
增强容错能力:引入了超时机制和预提交日志,使得参与者可以在协调者故障的情况下自主决定是继续提交还是回滚事务,从而减少了对协调者的依赖,并提高了系统的可用性和灵活性。
-
优化资源利用:因为CanCommit阶段并不锁定资源,只有在PreCommit阶段才会进行资源准备,这有助于更有效地利用系统资源。
缺点
尽管三阶段提交协议解决了以上问题,但同时也引入了新的麻烦:
-
复杂度增加:相较于2PC,3PC引入了额外的阶段和机制,增加了实现和维护的复杂性。
-
数据不一致风险:尽管3PC试图解决2PC的一些问题,但在某些情况下(如preCommit阶段协调者故障),仍然有可能出现数据不一致的问题。这是因为并非所有参与者都能在同一时刻感知到协调者的状态变化。
-
网络开销增大:由于3PC需要更多的通信轮次来完成一个事务(询问、预提交、提交),因此在网络环境较差或存在高延迟的情况下,可能会带来额外的性能损失。