Why is two-phase commit better than naive master-slave replication? 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.
You are confusing the purpose of the algorithms. The 2PC is a voting algorithm where the two sides have different data and different criteria for choosing a vote. The master-slave is a redundancy algorithm that aims to have identical copies at two places.

Besides, your master-slave is asynchronous where you return to client before replication. The client sees completion but the master can still become irrecoverable before replication, at which point you have data loss. 2PC is not subject to this.

That said, organizations may use 2PC in to implement master-slave, by making the “slave” always vote yes. This is essentially master-slave in synchronous mode, with unnecessary message overhead.

What you want to advocate for is probably synchronous master-slave, where you return to client after the slave confirms. It’s faster than 2PC because you only need one message exchange for each slave, instead of the two exchanges required for 2PC.