2PC与3PC

是什么

In transaction processing, databases, and computer networking, the two-phase commit protocol (2PC) is a type of atomic commitment protocol (ACP).

可以理解为一个协议,目的是解决分布式系统中的一致性问题的,也就是CAP中的C(consistency)。

2PC的过程

直接参考wiki上的流程如下:


Coordinator                                         Cohort
                              QUERY TO COMMIT
                -------------------------------->
                              VOTE YES/NO           prepare*/abort*
                <-------------------------------
commit*/abort*                COMMIT/ROLLBACK
                -------------------------------->
                              ACKNOWLEDGMENT        commit*/abort*
                <--------------------------------  
end

2PC的优缺点

The greatest disadvantage of the two-phase commit protocol is that it is a blocking protocol. If the coordinator fails permanently, some cohorts will never resolve their transactions: After a cohort has sent an agreement message to the coordinator, it will block until a commit or rollback is received.

优点是协议简单,同步的方式,实现上是方便的。但是最大的问题也是简单——同步,也就是上面这段说明的“After a cohort has sent an agreement message to the coordinator, it will block until a commit or rollback is received.”,这里不仅仅是同步的,而且是阻塞的,一个参与者必须同步阻塞地等待协调者的commit或者rollback消息,不能进行其他任何事情(阻塞),显然,这种方式吞吐量和响应时间都会很差。

而且,两阶段提交中有个场景会造成数据的不一致。

A two-phase commit protocol cannot dependably recover from a failure of both the coordinator and a cohort member during the Commit phase. If only the coordinator had failed, and no cohort members had received a commit message, it could safely be inferred that no commit had happened. If, however, both the coordinator and a cohort member failed, it is possible that the failed cohort member was the first to be notified, and had actually done the commit. Even if a new coordinator is selected, it cannot confidently proceed with the operation until it has received an agreement from all cohort members, and hence must block until all cohort members respond.

这种场景是,在协调者和参与制在第二个阶段同时崩溃的场景。

因为第一个阶段是个投票的阶段,既然是投票么,非常有可能一部分参与者投了个反对票,那么在协调者角度,非常有可能协调者并没有同意commit。所以如果在第二阶段提交后协调者自己崩溃了,那么这些参与者会推断协调者并没有进行事务的提交,因为从其中一个参与中角度看,它并不知道其他的参与者投票的是赞成还是反对票,所以在协调者崩溃后,参与者正常合理的推断是协调者并没有commit事务。

如果协调者和一部分参与者同时崩溃,又恰好,协调者崩溃前发送的是commit,又恰好,这些commit只到达了要崩溃的参与者其他正常的没有发送到,然后协调者和收到commit并执行后的参与者崩溃了。根据上面的分析,那些没有收到commit的参与者会默认事务是没有commit掉的。但是,由于上面说的多个恰好,崩溃的那个参与者commit了事务,而且又过了一会恢复了。这个时候就麻烦了,新选举出来的协调者是对这个事务怎么看呢?这就需要在这些参与者之前先取得一致,解决掉这个不一致的状态。但是同时崩溃的可能有多个参与者(又恰好都收到了commit),commit和未commit的参与者数目都有可能是一样的,所以处理还是比较麻烦的。

3PC过程

3PC解决的问题

首先3PC把2PC的第二个阶段,分成了两个阶段,预提交和doCommit

The three-phase commit protocol eliminates this problem by introducing the Prepared to commit state. If the coordinator fails before sending preCommit messages, the cohort will unanimously agree that the operation was aborted. The coordinator will not send out a doCommit message until all cohort members have ACKed that they are Prepared to commit. This eliminates the possibility that any cohort member actually completed the transaction before all cohort members were aware of the decision to do so (an ambiguity that necessitated indefinite blocking in the two-phase commit protocol).

The pre-commit phase introduced above helps us to recover from the case when a participant failure or both coordinator and participant node failure during commit phase. When the recovery coordinator takes over after coordinator failure during commit phase of two-phase commit, the new pre-commit comes handy as follows: On querying participants, if it learns that some nodes are in commit phase then it assumes that previous coordinator before crashing has made the decision to commit. Hence it can shepherd the protocol to commit. Similarly, if a participant says that it doesn’t receive PrepareToCommit message, then the new coordinator can assume that the previous coordinator failed even before it completed the PrepareToCommit phase. Hence it can safely assume no other participant would have committed the changes and hence safely abort the transaction.

总结下,二阶段的方式,在协调者与参与者同时崩溃,并且协调者只给这参与者刚发了commit,而且也commit.这个时候同时崩溃.新的出来的协调者一看,大家都没有commit,那我就先继续?继续后后续处理后那个commit的起来就很麻了.其实最重要的问题是不确定性,这个时候,大家都不能确定崩溃前是否协调者commit了,除非等那个崩溃的节点启动好.

三阶段提交,能解决这问题?感觉只能解决一半的问题,无法避免数据的不一致.通过引入这preCommit的状态,最主要就解决了超时的问题,变成一个”非阻塞”的协议.这preCommit的状态能增加一定的可靠性:

When receiving a pre-commit message, participants know that all others have voted to commit. If a pre-commit message has not been received the participant will abort and release any blocked resources.

在preCommit后如果超时没有收到commit会自动commit.

还有一点,比两阶段提交,在commit阶段如果两者都挂了,那么如果有一个参与者说自己没有收到preCommit的消息,那么可以推断出挂掉的参与者肯定是没有commit的.因为commit相当于一个屏障,只有大家都发了preCommit后才会发出commit的消息.

其他的,如果剩下的有收到commit,说明挂掉也是发出国preCommit的.但这和二阶段提交一样,二阶段提交中,如果有一个收到了commit说明事物是可以以commit的方式完成的.

但是,三阶段提交,如果也是两者同时在commit阶段挂了,其他参与者状态都是preCommit的状态,那么也不好判断但是挂掉的参与者是commit还是连preCommit都没有发送过,根据三阶段者非阻塞的特性,处理方式应该是当成事物需要commit处理,可能造成不一致.还是那就,三阶段只解决了部分不一致的问题,最重要的是非阻塞的协议.

3PC的优缺点

The main disadvantage to this algorithm is that it cannot recover in the event the network is segmented in any manner. The original 3PC algorithm assumes a fail-stop model, where processes fail by crashing and crashes can be accurately detected, and does not work with network partitions or asynchronous communication.

3PC其实解决了在接入阶段3后,协调者出现问题或参与者与协调者出现网络故障,参与者能够正常的提交,达到事务的一致性。这里不仅仅是好在“默认commit”相对于2PC的“默认不commit”,而是好在“超时后默认commit”与“默认一直阻塞不commit”,提不提交的不是重点,阻塞与不阻塞才是重点。

与“默认不commit”一样,默认commit同样会造成数据的不一致,例如一个参与者收到preCommit后然后网络出现分析,协调者无法与参与者通信,会发出abort请求,在一个网络分区中的参与者会回滚事务,而那个孤零零的参与者,自己默默地commit掉,会造成不一致的问题。

The protocol requires at least three round trips to complete, needing a minimum of three round trip times (RTTs). This is potentially a long latency to complete each transaction.

现场,对了此消息的交互,对于正常过程而言,会有一定的延迟。

Table of Contents