Replication exists to answer one question with many answers: how do you keep copies of the same data and decide which copy is authoritative? The topology you choose trades three things against each other — write latency, read consistency, and data loss on failure — and the trade is visible in every benchmark you've ever seen.
Synchronous vs asynchronous: the durability dial
The first axis is when a write is acknowledged:
- Synchronous replication: the primary blocks the commit until at least one replica has durably applied the write. Every commit now costs an extra network round trip: 0.5-3ms in the same region, 30-150ms cross-region. You gain the guarantee that a committed write survives a primary crash — assuming the replica was reachable, which is the catch: a slow or down replica blocks all writes. Synchronous replication converts a replica outage into a write outage.
- Asynchronous replication: the primary commits and acknowledges, and the replica catches up in the background. Writes return at local speed. The price is a lag window — typically 1-50ms same-region, hundreds of milliseconds to seconds cross-region, and unbounded under load spikes — during which the primary can die and take every un-replicated write with it. The failover can lose writes you already told clients succeeded.
Postgres synchronous_commit and MySQL semi-sync are the middle path: wait for one replica (so you have a hot standby) without waiting for all of them. "One" is the number that makes failover lossless while keeping write latency to a single regional RTT.
Single leader: the ordering machine
The most common topology is one writer, many readers: all writes go to the primary, replicas stream the WAL (Postgres) or binlog (MySQL) and apply it in order. The behavior is dead simple — every replica applies the same log in the same order, so any replica converges to a consistent snapshot. Reads scale horizontally; writes are bottlenecked on one node.
Read-your-writes is the gap: a client writes to the primary, then reads from a replica that hasn't applied the write yet. The fix is routing, not replication — pin a client's reads to the primary for a short window after its writes, or track a session watermark (a replica must be past sequence X before serving this session):
read(key, session):
pos = session.last_write_lsn # position of client's last acknowledged write
replicas = replicas_where(replay_position >= pos)
if replicas: return read_from(replicas.random())
return read_from(primary) # no replica is safe: leader servesEvery serious multi-region read-replica architecture implements one of those two, usually both.
Quorum systems: read-your-writes by arithmetic
Dynamo-style leaderless replication (Cassandra, Riak, Scylla) makes every replica equal and lets the client decide how many must agree: write to W of N nodes, read from R of N nodes, with W + R > N. The arithmetic does the consistency work:
- 3 nodes, W=2, R=2: tolerate one node being down and guarantee any read quorum overlaps the latest write — two sets of size 2 in a 3-element universe always intersect.
- 5 nodes, W=3, R=3: same property, two-failure tolerance.
Read-your-writes becomes a property of the math instead of routing logic: the write touched W nodes, so any R-read must include one of them. The costs are real: every read and write fans out to multiple nodes (3-5 network calls instead of 1), each operation waits for its slowest quorum member, and concurrent writers to the same key need conflict resolution — last-writer-wins by timestamp, or vector clocks the application must handle.
Lag: the master variable
Whatever the topology, replication lag is the number that breaks things. It turns into three observable phenomena:
- Read-after-write violations — a client sees its own write disappear as it migrates between replicas.
- Monotonic read violations — a client's reads jump backwards in time across replicas.
- Write conflicts — two clients concurrently write divergent values; with async replication and no quorum, both can be acknowledged and both survive.
Lag is also a measurement problem: pg_stat_replication shows replay position per standby, and alerting on lag above 2x its baseline (say, >500ms) catches the spikes that turn 20ms of lag into 20 seconds.
Chain and cascade topologies: lag multipliers
A replica can serve as the source for another replica (cascade in Postgres, chains in MongoDB). This cuts primary load — the WAL ships to one node, not ten — and every hop adds latency, turning a 10ms follower into a 30-100ms leaf. Cascades suit read-heavy analytics where staleness of seconds is acceptable; they are a bad fit for read-your-writes routing, which now has two lag legs to reason about.
The honest summary
Synchronous makes loss less likely and writes slower; asynchronous is the reverse. Leaderless buys availability at the cost of fan-out and conflict resolution. The topology that "wins" is the one whose failure mode you can afford: if losing acknowledged writes is unacceptable, you pay the latency; if write latency is the product, you accept the lag. Replication is a risk budget — pick the topology that spends it where your customers actually feel it.