Lesson 27 of 30
Replication and CAP
Replication keeps copies of the same data on several servers to survive failures, serve more reads, and place data near users. See also database replication.
Example 1: leader-follower replication
One leader (primary) accepts writes and streams changes to followers (replicas, standbys), which serve reads.
flowchart LR
C["Clients (writes)"] --> L["Leader"]
L -->|"WAL / binlog stream"| F1["Follower 1"]
L -->|"WAL / binlog stream"| F2["Follower 2"]
R["Clients (reads)"] --> F1
R --> F2| Term | PostgreSQL | MySQL |
|---|---|---|
| Change stream | WAL | Binary log (binlog) |
| Leader | Primary | Source (primary) |
| Follower | Standby (hot standby allows reads) | Replica |
Example 2: synchronous, asynchronous, semi-synchronous
The commit returns to the client after different events depending on the mode.
| Mode | Commit returns after | Data loss on leader crash | Write latency |
|---|---|---|---|
| Asynchronous | Leader wrote locally | Possible (recent commits not yet sent) | Lowest |
| Semi-synchronous | At least one follower received the change | Very unlikely | Medium |
| Synchronous | Follower(s) confirmed (received, flushed, or applied) | None for the confirmed level | Highest; a slow follower slows writes |
PostgreSQL controls this with synchronous_commit (off, local, remote_write, on, remote_apply) and synchronous_standby_names. MySQL has semi-synchronous replication as a plugin and Group Replication for consensus-based commit.
SELECT name, boot_val, short_desc
FROM pg_settings
WHERE name IN ('synchronous_commit', 'wal_level', 'max_wal_senders', 'hot_standby')
ORDER BY name; name | boot_val | short_desc
--------------------+----------+-------------------------------------------------------------------------
hot_standby | on | Allows connections and queries during recovery.
max_wal_senders | 10 | Sets the maximum number of simultaneously running WAL sender processes.
synchronous_commit | on | Sets the current transaction's synchronization level.
wal_level | replica | Sets the level of information written to the WAL.
(4 rows)Example 3: replication lag and read-your-writes
Asynchronous followers apply changes after the leader. A read from a follower right after a write can return old data.
sequenceDiagram
participant U as User
participant L as Leader
participant F as Follower
U->>L: UPDATE profile
L-->>U: OK
L-->>F: replicate (delayed)
U->>F: SELECT profile
F-->>U: old value| Anomaly | Meaning | Fix |
|---|---|---|
| Read-your-writes violation | User does not see their own write | Read own recent data from the leader, or track the write's LSN and wait for a follower to reach it |
| Monotonic reads violation | User sees newer data, then older data from another follower | Pin a user to one follower |
| Consistent prefix violation | Effects seen before causes | Keep related writes on one partition or use causal ordering |
Lag in bytes is the difference between WAL positions (pg_lsn values subtract to a byte count):
SELECT '0/3000128'::pg_lsn - '0/3000000'::pg_lsn AS lag_bytes; lag_bytes
-----------
296
(1 row)Example 4: monitoring replication in PostgreSQL
On a primary, pg_stat_replication has one row per connected standby. This server has no standby, so the view is empty; the column list shows what it reports.
SELECT count(*) AS connected_standbys FROM pg_stat_replication; connected_standbys
--------------------
0
(1 row)SELECT column_name
FROM information_schema.columns
WHERE table_name = 'pg_stat_replication'
AND column_name IN ('client_addr', 'state', 'sent_lsn', 'write_lsn', 'flush_lsn',
'replay_lsn', 'write_lag', 'flush_lag', 'replay_lag', 'sync_state')
ORDER BY ordinal_position; column_name
-------------
client_addr
state
sent_lsn
write_lsn
flush_lsn
replay_lsn
write_lag
flush_lag
replay_lag
sync_state
(10 rows)| Column | Meaning |
|---|---|
sent_lsn |
WAL sent to the standby |
write_lsn, flush_lsn |
WAL written and flushed on the standby |
replay_lsn |
WAL applied and visible to queries on the standby |
replay_lag |
Time between local flush and replay confirmation |
sync_state |
async, potential, sync, or quorum |
On a standby, pg_is_in_recovery() returns true.
Example 5: failover
When the leader fails, a follower is promoted.
flowchart LR
A["Detect failure (timeout)"] --> B["Choose the most up-to-date follower"]
B --> C["Promote it to leader"]
C --> D["Repoint clients and other followers"]
D --> E["Old leader rejoins as follower (rewind if diverged)"]| Risk | Cause |
|---|---|
| Lost writes | Async follower promoted while behind |
| Split brain | Two nodes both act as leader; prevented by fencing and a consensus-based coordinator |
| False failover | Timeout too short during a load spike |
Tools: Patroni, repmgr, and managed services for PostgreSQL; Orchestrator and Group Replication for MySQL. pg_rewind resynchronises a former leader.
Example 6: multi-leader and leaderless replication
| Model | Writes go to | Conflicts | Examples |
|---|---|---|---|
| Leader-follower | One leader | None | PostgreSQL, MySQL |
| Multi-leader | Any leader (often one per region) | Possible; resolved by last-write-wins, merge, or application logic | MySQL Group Replication multi-primary, BDR, Galera |
| Leaderless | Any replica | Possible; resolved by versions (vector clocks) and read repair | Cassandra, DynamoDB, Riak |
Example 7: quorum reads and writes (W + R > N)
With N replicas, a write waits for W acknowledgements and a read queries R replicas. If W + R > N, every read set overlaps every write set in at least one replica, so a read sees the latest acknowledged write.
| N | W | R | W + R > N | Behaviour |
|---|---|---|---|---|
| 3 | 2 | 2 | 4 > 3 yes | Strong; tolerates 1 node down for both reads and writes |
| 3 | 1 | 1 | 2 > 3 no | Fast, may read stale data |
| 3 | 3 | 1 | 4 > 3 yes | Fast reads; writes fail if any node is down |
| 5 | 3 | 3 | 6 > 5 yes | Tolerates 2 nodes down |
Worked case (N = 3, W = 2, R = 2): a write is stored on nodes A and B, node C misses it. Any 2 nodes read from {A,B}, {A,C}, or {B,C}. Each pair includes A or B, so the newest version is always returned and the coordinator returns the highest version. The query checks the overlap condition for several settings:
SELECT n, w, r, (w + r > n) AS overlap_guaranteed
FROM (VALUES (3,2,2), (3,1,1), (3,3,1), (5,3,3), (5,2,2)) AS q(n, w, r); n | w | r | overlap_guaranteed
---+---+---+--------------------
3 | 2 | 2 | t
3 | 1 | 1 | f
3 | 3 | 1 | t
5 | 3 | 3 | t
5 | 2 | 2 | f
(5 rows)Example 8: physical vs logical replication, statement vs row-based
| Physical (streaming) | Logical | |
|---|---|---|
| Ships | WAL bytes (block changes) | Decoded row changes (INSERT, UPDATE, DELETE) |
| Replica | Identical copy, same major version | Can differ in version, schema, and indexes |
| Granularity | Whole cluster | Selected tables (publication / subscription) |
| Replica writable | No (read-only standby) | Yes |
| Uses | High availability, read replicas | Upgrades across versions, selective copy, CDC (change data capture) |
MySQL binlog formats:
| Format | Logs | Trade-off |
|---|---|---|
STATEMENT |
The SQL text | Small, but non-deterministic functions (UUID(), NOW()) can diverge |
ROW |
Each changed row | Deterministic and the default; larger logs |
MIXED |
Statement unless unsafe, then row | Compromise |
Example 9: replica reads and connection pooling
Read replicas offload SELECT traffic. The application or a proxy routes writes to the leader and tolerant reads to followers.
| Concern | Handling |
|---|---|
| Stale reads | Route read-your-writes traffic to the leader |
| Long queries on standby conflict with WAL replay | hot_standby_feedback, max_standby_streaming_delay |
| Too many connections | Pool connections |
A PostgreSQL connection is a separate process using several MB of memory, so thousands of direct connections degrade the server. PgBouncer (or a built-in pool such as RDS Proxy) multiplexes many client connections onto a small number of server connections.
| Pool mode (PgBouncer) | Server connection held for | Restriction |
|---|---|---|
| Session | The whole client session | None |
| Transaction | One transaction | No session state (SET, advisory locks, prepared statements need care) |
| Statement | One statement | No multi-statement transactions |
Example 10: CAP, PACELC, and consistency models
CAP theorem: during a network partition (P) a distributed system must choose between consistency (C: every read sees the latest write) and availability (A: every request gets a non-error answer). Partitions cannot be ruled out in practice, so the real choice is CP or AP during a partition.
| Type | During a partition | Examples |
|---|---|---|
| CP | Rejects or blocks requests on the minority side | etcd, ZooKeeper, HBase, MongoDB (default majority writes), Spanner |
| AP | Answers from any node, may be stale | Cassandra, DynamoDB (eventual reads), Riak |
PACELC extends it: if there is a Partition choose A or C; Else (normal operation) choose Latency or Consistency.
| System | If partition | Else |
|---|---|---|
| Cassandra, DynamoDB (default) | PA | EL |
| Spanner, VoltDB | PC | EC |
| MongoDB | PA | EC |
Consistency models from strongest to weakest:
| Model | Guarantee |
|---|---|
| Linearizable | Operations appear to happen instantly in real-time order |
| Sequential | All see operations in the same order, not necessarily real-time |
| Causal | Cause is seen before effect |
| Read-your-writes / monotonic reads | Per-client guarantees |
| Eventual | Replicas converge if writes stop |
The consistency in CAP (linearizability) is different from the C in ACID (constraints hold).
Interview points
- Async replication can lose committed data on failover; sync replication costs latency and availability.
- Replication lag causes read-your-writes and monotonic-read anomalies.
- W + R > N gives overlapping quorums.
- Physical replication copies WAL; logical replication copies row changes and supports version upgrades.
- CAP applies only during partitions; PACELC covers the latency trade-off otherwise.
- Replicas scale reads, not writes; sharding scales writes.
Summary
- Leader-follower replication streams the WAL or binlog to followers; async is fast but can lose data, sync is safe but slower.
- Lag produces stale reads; route read-your-writes traffic to the leader.
- Failover needs failure detection, promotion, and fencing to avoid split brain.
- Leaderless systems use quorums: W + R > N ensures a read overlaps the latest write.
- CAP forces CP or AP during a partition; PACELC adds the latency vs consistency choice otherwise.
