ποΈ 29042026 1715
π #database #replication
The three replication acknowledgement modes. The difference between them is whether recently-committed data survives the next leader crash β and how much latency you trade for that guarantee.
The Three Modesβ
Asynchronous β leader commits + acks the client. Replicas catch up later. Synchronous β leader waits for all replicas to ack before responding to the client. Semi-synchronous β leader waits for at least one replica to ack before responding.
| Mode | Leader-side latency | Data loss on leader crash | Throughput |
|---|---|---|---|
| Async | RTT(leaderβdisk) | Up to replication lag of writes | Highest |
| Semi-sync | RTT(leaderβdisk) + RTT(replica) | Bounded β at least one replica has it | Medium |
| Sync (all) | RTT(slowest replica) | Zero | Lowest, slowest replica caps you |
When Each Is Usedβ
- MySQL default: async. Simple, fast, accepts data-loss risk on failover.
- MySQL
rpl_semi_sync: opt-in semi-sync. Used by many production deployments wanting bounded loss without all-replica wait. - PostgreSQL
synchronous_standby_names: configurable list, supportsANY n(semi-sync-style) andFIRST n(priority-based). - Spanner / CockroachDB: synchronous via Paxos/Raft quorum (W = majority).
- Galera / InnoDB Cluster: synchronous multi-write via group communication.
What "Synchronous" Actually Meansβ
Pure all-replica sync is rare in practice β one slow replica drags down the entire cluster. Real "sync" usually means quorum sync (e.g. majority via raft or Paxos). quorum_reads_writes is the formal model.
Calling MySQL rpl_semi_sync "synchronous" is loose: it ensures one replica got the write, not that the replica has applied it. There's a window between "ack received" and "applied" where reading from that replica is still stale.
Replication Lagβ
Async + semi-sync replicas apply changes after they're received. The delay = replication lag. Sources:
- Network RTT between leader and replica.
- Replica's apply throughput (single-threaded SQL apply was MySQL's classic bottleneck β fixed somewhat by parallel apply since 5.7).
- Replica is also serving reads β apply gets queued.
Lag β read-after-write inconsistency: write to leader, read from replica, don't see your own write. Mitigations:
- Read your own writes from leader.
- Wait for replica to confirm position (
MASTER_POS_WAITin MySQL). - Stick the user to one replica (sticky sessions).
- Use synchronous reads from leader for sensitive paths.
Logical vs Physicalβ
- Physical (Postgres WAL streaming, MySQL row-based binlog): bytes-level replay. Tight coupling between versions; replicas are byte-identical.
- Logical (statement-based, or logical decoding output): replays high-level changes. Loose coupling; can replicate across major versions or different schemas. Used for CDC tools (Debezium reads MySQL row-based binlog; Postgres logical decoding feeds it).
MySQL binlog has three formats: STATEMENT, ROW, MIXED. ROW is the production default β deterministic, no nondeterministic-function issues.
Replication Topologiesβ
| Topology | Description | Used in |
|---|---|---|
| Single-leader | One writer, N readers. Most common. | MySQL/Postgres default |
| Multi-leader | Multiple writers, conflict resolution required. | Multi-region setups, BDR |
| Leaderless | All nodes accept writes; quorum reads/writes. | Cassandra, Dynamo |
Failoverβ
- Async + leader crash β some recently-committed-on-leader writes are gone. Acceptable for many use cases (tolerate 1β10s of lost writes during failover).
- Semi-sync + crash β at least one replica had the write. Promote that one. Zero loss IF the right replica is promoted.
- Sync (quorum) + crash β majority has the write. Always-correct failover. This is the pitch for Raft-backed systems.
Split brain risk during failover: old leader doesn't know it lost the role and accepts writes. Mitigations: fencing tokens, lease timeouts, STONITH ("shoot the other node in the head").
Common Pitfallsβ
- Async is MySQL's default for throughput β most workloads tolerate the small data-loss window during a rare failover.
- Semi-sync is best-effort, not a hard guarantee β if all replicas are unreachable, MySQL falls back to async after a configurable timeout. The replica-acked-write guarantee disappears in that window.
- Pure synchronous all-replicas blocks forever if one replica is slow β which is why real systems use semi-sync or quorum-based sync, not all-replicas sync.
- Reading your own writes from a replica has no zero-cost answer β wait for the replica to catch up to the leader's position, read from the leader, or pin the session to one replica.
- Parallel apply is tricky β out-of-order replay can violate constraints. MySQL keys parallelism on schema or per-database to bound the race.
Relatedβ
- raft β quorum-based "synchronous" replication done right.
- quorum_reads_writes β N/W/R formalism.
- cap_theorem β async = AP-leaning, sync-quorum = CP-leaning.
read_write_splitting_replication_lag(planned) β application-side patterns.
Referencesβ
- "Designing Data-Intensive Applications" ch. 5
- MySQL docs: Replication Modes
- PostgreSQL docs: Synchronous Replication