2-Phase Commit (2PC)
Let's explore how the 2-phase commit algorithm helps to achieve atomicity.
In a distributed system with an unreliable network, just sending a message to the involved nodes would not be enough for executing a distributed transaction. The node initiating the transaction would not know whether the other nodes committed successfully, or aborted because of some failure, to make a final decision about the result of the transaction.
When we think about it, the simplest idea is to add another round of messages, and check what the result was on each node. This is essentially the
2-phase commit protocol J. N. Gray, “Notes on database operating systems,” Operating Systems. Lecture Notes in Computer Science, vol 60. Springer, 1978. . (2PC) B. Lampson and H. E. Sturgis, “Crash Recovery in a Distributed Data Storage System,” 1979.
Phases
The 2-phase commit protocol consists of two phases, hence the name.
The protocol contains two different roles. Their names reflect their actual responsibilities in the protocol.
-
The coordinator is responsible for coordinating the different phases of the protocol
-
The participants correspond to all the nodes that participate in the transaction
Note that one of the participants could also play the role of the coordinator.
Voting phase
In this phase, the coordinator sends the transaction to all the participants. The participants execute the transaction up to the point where they are supposed to commit.
In some cases, the operations of each transaction are executed separately and before the voting phase, which starts after all the operations of a transaction has been executed. Agreement protocols like this usually involve some locking protocol as well, so that other concurrent transactions cannot make participants that have already voted change their mind on whether they can commit or not. For example, the 2-phase commit protocol can be combined with the 2-phase locking protocol.
Then, participants respond to the coordinator with a vote that shows if the transaction’s operations are executed successfully (“Yes” vote) or there is some error that means the transaction cannot be committed (“No” vote).
Commit phase
In this phase, the coordinator gathers all the votes from the participants. If all the votes are “Yes”, then the coordinator messages the participants again with an instruction to commit the transaction.
Otherwise, if at least one vote is “No”, the coordinator instructs the participants to abort the transaction. Finally, the participants reply with an acknowledgment and close this phase.
The fact that a unanimous positive vote is needed for a commit means that the transaction will either commit to all the participants, or will be aborted to all of them (atomicity property).
The coordinator and the participants make use of a write-ahead-log, where they persist their decisions during the various steps so that they can recover in case of a failure.
The coordinator also uses a timeout when waiting for the responses from the first phase. If the timeout expires, the coordinator interprets this timeout as a No vote and considers the node as failed.
On the other hand, the participants do not apply any timeouts while waiting for the coordinator’s messages, since that could lead to participants reaching different conclusions due to timing issues.
The following illustration shows what this flow looks like.
Handling failures
Since the happy path is straightforward, let’s examine how the protocol handles various kinds of failures.
Failure of a participant in the voting phase
If a participant fails in the voting phase before replying to the coordinator, the coordinator will timeout waiting and assume a No vote on behalf of this participant.
This means that the protocol will end up aborting the transaction.
Failure of a participant in the commit phase
In this scenario, a participant votes in the voting phase but then fails before it receives the message from the coordinator and completes the transaction (either by committing or abort).
In this case, the protocol will conclude without this node. If this node recovers, later on, it will identify that pending transaction and communicate with the coordinator to find out what the result was, and conclude it in the same way.
So, if the result of the transaction is successful, any crashed participant will eventually find out upon recovery and commit it. The protocol does not allow aborting it unilaterally. Thus, atomicity is maintained.
Some readers may have noticed that there is a chance that the participants may fail at the point they try to commit the transaction and break their promise, e.g., because they are out of disk space. Indeed, this is true. Thus, participants have to make the minimum work possible as part of the commit phase to avoid this. For example, the participants can write all the necessary data on the disk during the first phase so that they can signal a transaction is committed by doing minimal work during the second phase (e.g., flipping a bit).
Network failures
Network failures have similar results to those described previously, since timeouts make them equivalent to node failures.
Even though a 2-phase commit can handle all the aforementioned failures gracefully, there’s a single point of failure: the coordinator.
Blocking nature of 2-phase commit protocol
Because of the blocking nature of the protocol, failures of the coordinator at specific stages of the protocol can bring the whole system to a halt. More specifically, if a coordinator fails after sending a prepared message to the participants, the participants will block. The participants will wait for the coordinator to recover and find out the outcome of the transaction, so that they commit or abort it as needed.
This means that failures of the coordinator can decrease the availability of the system significantly. Moreover, if the data from the coordinator’s disk cannot be recovered (e.g., due to disk corruption), the result of pending transactions cannot be discovered, and manual intervention might be needed to unblock the protocol.
Usage of the 2-phase commit protocol
Despite the blocking nature of the protocol, the 2-phase commit is widely used. A specification, called the eXtended Architecture (XA), has also been released.
In this specification, each of the participant nodes is referred to as resources, and they must implement the interface of a resource manager.
The specification also defines the concept of a transaction manager that acts as the coordinator that starts, coordinates, and ends transactions.
Conclusion
The 2PC protocol satisfies the safety property that ensures all participants always arrive at the same decision (atomicity). However, it does not satisfy the liveness property that implies it will always make progress.
Get hands-on with 1400+ tech skills courses.