In the context of a distributed database, I'm trying to understand why 2PC (as described in e.g. https://www.cs.princeton.edu/courses/archive/fall16/cos418/docs/L6-2pc.pdf) is better than the following hypothetical protocol between a client, master, and slave:
- client tells master to commit
- master commits it
- master tells client the commit succeeded
- master tells slave to replicate the commit. If the slave fails, master keeps on trying until it succeeds and gets the slave caught up on all edits.
This seems to me to satisfy the same properties as 2PC:
- Safety: If the master commits, the slave will also eventually commit. If the slave commits, the master must have committed first. I suppose an advantage of 2PC is that if a participant fails before starting the commit, the transaction will be failed instead of only committing on the TC. However, in the proposed protocol, the commit on the master still eventually gets to the slave.
- Liveness: This protocol does not hang.
- Both rely on the master / TC durably recording the decision to commit. Both assume failed slaves / participants eventually wake up and catch up with the master / TC.
- Both fail if the master / TC goes down.
- In both protocols, it's possible to have temporary inconsistencies where the master / TC has finalized a decision, but the slaves / participants haven't yet committed.
It seems to me that the key theoretical difference in 2PC is that the participant (slave) can vote "no" to the commit, as opposed to merely temporarily failing. That would break the conclusion above where the slave eventually catches up. However, I don't see why the slave would need to vote "no" in the first place. Given the assumption that the slave / participant does not permanently fail, it seems it should either vote "yes" or fail to respond. (Unlike the bank account example, I expect the slave to blindly replicate the master.)
Distilling all this down, it seems to me that 2PC's assumption that participants don't permanently fail makes it unnecessary to give participants a chance to vote "no" in the "prepare" phase.
What am I missing here? Presumably there's some advantage to 2PC over the above that I'm not understanding, since 2PC is actually used to build distributed databases.
- Am I incorrect in concluding that a slave shouldn't need to explicitly vote "no", as opposed to temporarily failing? (I'm only talking about the data replication use case, rather than the bank account example.)
- Given the same assumptions as 2PC, and assuming slaves only say "success" or "try again", is there some guarantee 2PC offers that the naive replication above doesn't?
For the purpose of the question, I'd like to ignore practicalities, unless they're critical to the answer. In particular, I'd like to ignore things that could be interpreted as being disallowed by the no-permanent-failure assumption, such as disk full, slave mis-configured, slave corrupt, operator error, buggy software, etc.