The full picture
| Mode | Ack after | RPO | Failure behaviour |
|---|---|---|---|
| Async | leader's own commit | seconds of writes | fast; silent data loss on failover |
| Semi-sync (1 replica) | leader + 1 follower | ≈0 for single-node loss | one slow replica → fallback or stall |
| Quorum (majority) | leader + majority | 0 for minority loss | the consensus default (Kafka acks=all, w:majority) |
| Full sync (all) | every replica | 0 | availability of the weakest node — effectively unusable |
// Kafka: acks=1 acknowledges on the leader only. A leader crash loses it.
props.put(ProducerConfig.ACKS_CONFIG, "all"); // wait for the in-sync replicas
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true); // no duplicates on retry
// ... and on the broker, min.insync.replicas=2, otherwise "all" can mean "just the leader"
// when the ISR has shrunk to one. Both settings are needed; either alone is a false sense
// of safety.
// MongoDB: the write concern travels with the operation.
collection.withWriteConcern(WriteConcern.MAJORITY) // durable across an election
.insertOne(order);
// Postgres: synchronous_commit + synchronous_standby_names decide the same trade-off.- Kafka's `acks=all` + `min.insync.replicas` pairing is the classic gotcha:
acks=allmeans 'all in-sync replicas', and if replicas have fallen out of the ISR that set can be just the leader. Withoutmin.insync.replicas=2you can lose acknowledged messages while believing you configured maximum durability. This is a genuinely common production incident. - Chained/cascading failure is the argument against full sync: with every replica required, your write availability is the product of each replica's availability — more replicas make you less available. Majority quorums invert that: more replicas make you more tolerant. Stating this inversion clearly is a strong signal.
- RPO and RTO are the vocabulary to use with stakeholders: RPO = how much data you may lose (set by replication mode), RTO = how long recovery takes (set by failover detection + election + cache warm-up). Product owners can reason about those numbers; 'async replication' means nothing to them.
- Failover isn't free even at RPO 0: detection timeout, election, client reconnection and a cold cache typically make the observable outage much longer than the election itself. Systems that look instantly failed-over in a demo take 30+ seconds under real load.
- The dangerous middle ground: async replication plus reads-from-replica plus automatic failover promotes a lagging replica and silently rolls back acknowledged writes. If you run async, either accept a manual failover step or use a store that refuses to promote a replica behind by more than a bounded amount.