Replication

What is it: Replication maintains copies of data on multiple servers. The primary (master) accepts writes; replicas (slaves) receive and replay the same changes, staying in sync.

Why: High availability — if the primary fails, a replica can be promoted to primary (failover). Read scalability — replicas can serve read queries, offloading the primary. Disaster recovery — replicas in different data centers survive regional failures.

sequenceDiagram participant C as Client participant P as Primary participant R as Replica Note over C,R: Synchronous C->>P: write P->>R: replicate R->>P: ack P->>C: commit acknowledged (RPO=0) Note over C,R: Asynchronous C->>P: write P->>C: commit acknowledged immediately P->>R: replicate (some delay)

Synchronous replication: Primary waits for at least one replica to confirm write receipt before acknowledging the commit to the client. Zero data loss (RPO = 0). Higher write latency — every commit incurs an extra network round trip to the replica. If the replica is slow or unreachable, primary commits are blocked (unless configured to fall back to async after timeout).

Asynchronous replication: Primary commits immediately without waiting for replica confirmation. Low write latency. Replication lag: replicas may be seconds behind the primary. On primary failure, committed transactions not yet replicated are lost (RPO > 0). The acceptable lag depends on the SLA.

Replication lag: The time between a write committing on the primary and that write being visible on the replica. Causes: network latency, replica I/O bottleneck, replica CPU load. Monitor as a metric (pg_stat_replication.write_lag).

Read-after-write consistency: A user writes data (updates their profile), then immediately reads it. If the read hits a replica with lag, the user sees stale data — their own update is missing. Mitigation: route the read to the primary for a short window after a write (sticky reads); or use the primary for all reads of data the user just wrote; or read from replicas only for data the user didn't write.

Trade-offs: Read replicas help with read scalability but do not help with write scalability — all writes still go to a single primary. For write scalability, sharding is needed.

Real-world usage: in a typical web app with 90% reads and 10% writes, adding 2 replicas triples read capacity without touching the primary. The primary handles 10% of traffic (writes), each replica handles 45% of traffic (reads) — a simple and highly effective scaling strategy.

Common pitfall

Routing all reads to replicas indiscriminately, including the read that immediately follows a user's own write, reproduces the read-after-write problem described above on every single "save and redirect back to the same page" flow — a pattern common enough that it shows up as an intermittent, hard-to-reproduce bug report ("sometimes my changes don't save") rather than an obvious one. Explicitly routing the read immediately following a write to the primary (or to whichever replica received it synchronously) is the direct fix, not a "just add more replicas" one.