Track 3: Replication Strategies
How to copy data across nodes while maintaining consistency guarantees. Replication is the foundation of both reliability and performance in distributed systems — it ensures your data survives machine failures and allows read traffic to be spread across multiple servers. But it comes with a fundamental tension: the more copies you maintain, the harder it is to keep them all in sync, especially when the network is slow or partitioned.Modules: 5
Key Topics: Single-leader, Multi-leader, Leaderless, Conflict Resolution, CRDTs
Module 11: Single-Leader Replication
The most common replication strategy.Synchronous vs Asynchronous Replication
- Synchronous
- Asynchronous
- Semi-Synchronous
- Follower guaranteed to be up-to-date
- No data loss on leader failure
- Higher latency
- Leader blocked if follower slow/dead
Replication Lag
Understanding Replication Lag
- Network latency between leader and followers — speed-of-light physics; a cross-region replica 5000km away has at minimum ~17ms RTT just from physics
- Follower processing slower than leader writes — the follower must apply writes in order, and a single slow query (e.g., index rebuild) stalls everything behind it
- Follower temporarily offline or restarting — when it comes back, it must replay the entire backlog before it is “caught up”
- High write throughput overwhelming followers — if the leader can write at 100K TPS but the follower’s disk can only sustain 80K TPS, the gap grows monotonically until you intervene
- Financial systems: Milliseconds
- Analytics: Minutes or hours acceptable
- Caching: Seconds to minutes
- Sticky sessions: Route user’s reads to same follower
- Read from leader: For critical reads after writes
- Version vectors: Track causality explicitly
Implementing Read-Your-Writes Guarantees
One of the most common consistency issues users experience. Here’s how to implement it:Handling Failover
│ │ │ STEP 1: DETECT LEADER FAILURE │ │ ───────────────────────────── │ │ • Heartbeat timeout (typically 10-30 seconds) │ │ • Multiple checks to avoid false positives │ │ │ │ STEP 2: ELECT NEW LEADER │ │ ──────────────────────── │ │ • Most up-to-date follower preferred │ │ • May use consensus (Raft) or controller node │ │ │ │ STEP 3: RECONFIGURE SYSTEM │ │ ───────────────────────── │ │ • Update clients to write to new leader │ │ • Other followers switch to new leader │ │ • DNS/load balancer update │ │ │ │ GOTCHAS: │ │ ──────── │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ SPLIT-BRAIN: Both old and new leader think they’re the leader │ │ │ │ DATA LOSS: Async replication means new leader may be behind │ │ │ │ CONFLICTS: Old leader comes back with conflicting writes │ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ │ │ GITHUB 2012 INCIDENT: │ │ MySQL failover caused data loss │ │ Auto-incrementing IDs reused → foreign key violations │ │ │ └─────────────────────────────────────────────────────────────────────────────┘- Multi-datacenter operation (write locally, replicate globally) — This is the most common. Write latency stays local (~1-5ms instead of cross-continent ~100-200ms). Trade-off: conflicts.
- Offline-capable clients (phone writes locally, syncs later) — CouchDB and PouchDB were designed specifically for this pattern. Your phone is essentially a “leader” that syncs when connectivity returns.
- Collaborative editing (each user has local leader) — Google Docs uses a variant of this combined with Operational Transform.
- LAST-WRITE-WINS (LWW) ──────────────────────── Use timestamps, highest timestamp wins
- MERGE VALUES ──────────────── Combine conflicting values
- CUSTOM RESOLUTION ──────────────────── Application-specific logic
- PROMPT USER ────────────── Show conflicts to user, let them choose
- ROUTE BY USER User’s writes always go to same leader No concurrent writes to same data
- ROUTE BY DATA Partition data, each partition has one leader
- GLOBAL LOCKING Acquire lock before write (defeats purpose of multi-leader though)
- CRDT DATA TYPES Data structures designed to merge without conflicts (covered in Module 15)
Dotted Version Vectors (DVV)
Traditional Version Vectors can grow linearly with the number of nodes ( overhead) and can be imprecise for concurrent updates to the same node. Dotted Version Vectors (DVV), used in Riak, solve this by separating the “dot” (a specific update) from the “causal context.” Key Benefit: DVVs accurately distinguish between “I have seen this update” and “This update is a sibling of that one,” leading to significantly fewer false conflicts during churn.Last-Write-Wins (LWW) Deep Dive
Application-Level Resolution
Module 15: CRDTs
Conflict-free Replicated Data Types - data structures that automatically merge.Counter CRDTs
- G-Counter (Grow-only)
- PN-Counter
CRDT Counter Visualization
- Redis: CRDT-based geo-replicated databases
- Riak: Uses CRDTs for distributed counters and sets
- Figma: Uses CRDTs for collaborative design
- Apple Notes: CRDTs for offline-first sync
Set CRDTs
- G-Set (Grow-only)
- 2P-Set (Two-Phase)
- OR-Set (Observed-Remove)
Register CRDTs
JSON CRDTs & Rich Text (Automerge/Yjs)
Modeling a simple counter or set is one thing, but how do you model a JSON Document or a Rich Text Document (like this one)?1. JSON CRDT Architecture
A JSON CRDT models the document as a Tree of CRDTs.- Objects: Maps where keys map to other CRDTs.
- Arrays: Sequences where each element has a unique ID and a pointer to the previous element (RGA - Replicated Growable Array).
- Registers: For leaf values (strings, numbers).
2. The Interleaving Problem
In collaborative text editing, if Alice inserts “A” and Bob inserts “B” at the same position, a naive CRDT might result in “BA” for Alice and “AB” for Bob. Modern CRDTs like Yjs and Automerge use Causal Ordering and Unique IDs to ensure that all replicas agree on the order (e.g., “AB” for everyone).Delta-CRDTs: Optimizing Bandwidth
The biggest drawback of State-based CRDTs (CvRDTs) is that the state grows over time. If you have a counter with 1,000 nodes, you must send all 1,000 counts every time you sync. Delta-CRDTs solve this by only sending the Delta (the changes) since the last successful synchronization.- Dot Store: A way to track which specific updates (dots) a neighbor has already seen.
- Delta-Group: A collection of updates that are merged together before being sent.
- Efficiency: Reduces bandwidth from to , making CRDTs viable for mobile devices on slow networks.
Garbage Collection & Tombstones
When you remove an element from a CRDT (like a2P-Set or OR-Set), you must keep a Tombstone to prove to other nodes that the item was deleted. If you delete the tombstone too early, a node that hasn’t seen the deletion might “re-infect” the cluster with the old data.
Strategies for Cleaning Tombstones:
- Stable State GC: Only delete a tombstone once you have proof (via gossip) that every node in the cluster has seen the deletion.
- Time-based GC: Delete tombstones after a very long period (e.g., 30 days). If a node stays offline longer than that, it must be completely wiped and re-synced from scratch.
CRDT Usage in Practice
Multi-Paxos / Raft Groups (Sharded Consensus)
A single consensus group (e.g., one Raft cluster) is bottlenecked by the CPU and I/O of a single leader. To scale to millions of requests, you must use Sharded Consensus.Architecture: Multi-Group
Instead of one large group, we partition the data into many small shards, each managed by its own independent consensus group.The Challenge: Cross-Shard Transactions
When an operation affects multiple shards (e.g.,Transfer($5) from Shard A to Shard B), you need a higher-level protocol like Two-Phase Commit (2PC) or Percolator to coordinate across the individual consensus groups.
Used By: CockroachDB (Ranges), TiDB (Regions), and Google Spanner (Paxos Groups).
Chain Replication
Chain replication is a widely used technique for high-throughput, linearizable replication. It is used in systems like FAWN and CORFU.Advanced Design Scenarios
Scenario 1: Global E‑Commerce Database Replication
You run a global e‑commerce platform with users in US, EU, and APAC. You want strong guarantees for orders and payments, but can tolerate slightly stale reads for product browsing. Design:- Topology:
- Single write leader region (e.g.,
us-east-1) with synchronous followers in the same region. - Read replicas per region (EU, APAC) receiving asynchronous replication from the leader.
- Single write leader region (e.g.,
- Write path:
- All order and payment writes go to the regional leader in
us-east-1. - Use semi-synchronous replication inside the leader region: commit after 1 follower ACK to avoid single-copy-of-truth.
- All order and payment writes go to the regional leader in
- Read path:
- Critical reads (order status, payment status): hit the leader region or only replicas with replication lag < T ms.
- Non-critical reads (product catalog, reviews): go to nearest regional replica even if seconds behind.
- RPO/RTO:
- With semi-sync in primary region, losing the leader does not lose committed transactions; failover to the in-region sync follower.
- Cross-region replication remains async → if the entire region fails, you may lose up to (Δ) seconds of writes that haven’t replicated.
- Patterns used:
- From this module: single-leader replication, sync vs async, replication lag awareness, and failover.
- Combined with consistency models: guarantee read-your-writes by routing post-write reads to the leader or using a
min_lsn/min_commit_timethreshold on replicas.
Scenario 2: Active‑Active User Profile Store
You want low-latency profile updates and reads from any region, and you’re willing to accept eventual consistency for some fields but not for others. Requirements:- Profile updates can happen in any region (multi-leader / active‑active).
- Some fields (e.g.,
email,phone) must avoid conflicting values. - Other fields (e.g.,
last_seen_at,recently_viewed) can be merged.
- Multi-leader replication between regions with a log for each leader.
- Per-field conflict resolution strategy:
- Identity fields (
email,phone,name): Last-Write-Wins per field with server-side timestamps (avoid whole-record LWW). - Activity fields (
recently_viewed,devices,tags): treat as CRDT sets or counters and merge.
- Identity fields (
- During a partition, each region continues accepting writes.
- On healing:
- For scalars, keep value with newer timestamp (assuming bounded skew, or use hybrid logical clocks).
- For sets/counters, apply CRDT merge (no conflicts).
- Multi-leader replication + conflict detection (version vectors or timestamps).
- Conflict resolution strategies and CRDTs for different fields in the same entity.
Scenario 3: Leaderless Metrics Store with Tunable Consistency
You’re designing a high-throughput metrics and logs store similar to Dynamo/Cassandra. Availability and write throughput matter more than strict consistency. Design:- Leaderless replication with parameters (N, W, R):
- (N = 3) replicas per key.
- For writes: (W = 2) for production metrics, (W = 1) for debug logs.
- For reads: (R = 1) for dashboards where staleness is acceptable, (R = 2) for alerting queries.
- Anti-entropy:
- Enable read repair on reads (update stale replicas in background).
- Periodically run Merkle tree comparisons between nodes to reconcile drift.
- Partial node failures: As long as at least (W) nodes are reachable for writes and (R) for reads, the system remains available with overlapping quorums.
- Sloppy quorums + hinted handoff:
- When a home replica is down, temporarily write to a substitute node (hinted handoff) to keep (W) high.
- On recovery, hints are replayed to repair the downed node.
- Trade-offs:
- For alerting: configure (W + R > N) and avoid sloppy quorums to favor correctness.
- For debug logs: allow (W = 1, R = 1) and sloppy quorums to maximize write availability.
- Quorum mathematics ((W + R > N)), sloppy quorums, hinted handoff, and anti-entropy techniques from this module in a concrete operational design.
Key Interview Questions
Q: When would you choose leaderless over leader-based replication?
Q: When would you choose leaderless over leader-based replication?
- High availability is critical (any node can accept writes)
- Write latency matters (write to nearest nodes)
- Can tolerate eventual consistency
- Multi-datacenter with no clear primary
- Need strong consistency
- Transactions required
- Simpler conflict resolution
- Read-heavy workload (scale reads with followers)
- Leaderless: Session data, user activity, metrics
- Leader: Financial transactions, inventory, user accounts
Q: Design conflict resolution for a shopping cart
Q: Design conflict resolution for a shopping cart
- Cart shared across devices
- Offline support
- Reasonable merge behavior
Q: How do you handle replication lag in a user-facing feature?
Q: How do you handle replication lag in a user-facing feature?
-
Read-your-writes consistency
- Track writes with client-side timestamp
- Read from replica that’s caught up
- Or read from leader for recently-written data
-
Monotonic reads
- Stick user to same replica (session affinity)
- Or track last-seen replica position
-
Synchronous replication for critical data
- Higher latency but guaranteed consistency
-
Application-level workaround
- Optimistic UI (assume success)
- Show cached data with “syncing” indicator
Q: Explain how Cassandra handles replication
Q: Explain how Cassandra handles replication
Next Steps
Continue to Track 4: Distributed Transactions
Interview Deep-Dive
Your team is debating between single-leader and leaderless replication for a new global service. Walk me through the trade-offs you would present.
Your team is debating between single-leader and leaderless replication for a new global service. Walk me through the trade-offs you would present.
- Single-leader replication (Raft-backed, primary-replica) gives you strong consistency guarantees with a simple mental model: all writes go to one node, followers replicate in order. The cost is that write latency equals the round-trip to the leader. If the leader is in US-East and a user in Tokyo writes, they pay 150ms+ cross-Pacific latency. Leader failure also causes a brief unavailability window during election (typically 1-5 seconds for Raft).
- Leaderless replication (Dynamo-style: Cassandra, Riak) removes the single-leader bottleneck. Any node can accept writes, so users write to the nearest replica with low latency. Reads are consistent if R + W > N (quorum overlap guarantees at least one node in the read set has the latest value). The cost is operational complexity: you need conflict resolution strategies, you lose serializability across keys, and sloppy quorums can break consistency guarantees.
- My recommendation depends on the workload. For a service requiring strong consistency (financial ledger, authentication tokens), I choose single-leader. For a service where availability and low latency matter more (user profiles, shopping carts, IoT telemetry), I choose leaderless. For the middle ground (social feeds, collaborative tools), I consider multi-leader with conflict resolution.
Explain replication lag and its impact on user experience. How would you detect and mitigate it in production?
Explain replication lag and its impact on user experience. How would you detect and mitigate it in production?
- Replication lag is the delay between a write committed on the primary and that write being visible on a follower. In single-leader systems with async replication, lag ranges from milliseconds (same DC) to seconds (cross-region), and can spike to minutes under load.
- The user experience impact is the “time travel” effect: a user writes data, gets success, then reads from a follower and does not see their own write. For example, a user posts a comment, the page refreshes hitting a follower, and the comment is missing.
- Detection: instrument replication lag as a first-class metric. For MySQL, monitor Seconds_Behind_Master. For PostgreSQL, monitor pg_stat_replication.replay_lag. Set alerts when lag exceeds your SLA.
- Mitigation: (1) Read-your-writes — after a write, route subsequent reads from the same session to the primary or a fresh replica. (2) Monotonic reads — pin sessions to a specific replica so users never go back in time. (3) Synchronous replication for critical paths — writes wait for at least one follower, reducing lag at the cost of latency. (4) If using Kafka, auto-scale consumers when lag grows.
How do CRDTs achieve eventual consistency without coordination, and what are their practical limitations?
How do CRDTs achieve eventual consistency without coordination, and what are their practical limitations?
- CRDTs are data structures where concurrent updates on different replicas can always be merged automatically. The merge operation is commutative, associative, and idempotent — updates arrive in any order, apply multiple times, and the result is always the same.
- A G-Counter is the simplest example: each replica maintains its own counter, the global count is the sum. Incrementing is local. Merging is element-wise max. A PN-Counter extends this with a separate decrement counter. An OR-Set supports add and remove by tagging each add with a unique ID.
- Limitations: (1) CRDTs can only express monotonically growing information, so operations like “set to exactly 5” require careful encoding with metadata overhead. (2) Metadata grows over time — tombstones, per-replica counters — and garbage collecting it requires the coordination CRDTs are designed to avoid. (3) CRDTs cannot express arbitrary invariants. A CRDT bank account cannot prevent negative balances because enforcing that constraint requires knowing global state.
Your Cassandra cluster uses quorum reads and writes (R=2, W=2, N=3). A network partition isolates one node. Walk me through what happens.
Your Cassandra cluster uses quorum reads and writes (R=2, W=2, N=3). A network partition isolates one node. Walk me through what happens.
- With strict quorum, clients can still read and write. One node is isolated, leaving 2 reachable. W=2 is satisfied by both available nodes. R=2 is satisfied by both available nodes. The system remains operational.
- The isolated node may serve requests from clients on its side of the partition. With strict quorums, those clients cannot form a quorum (only 1 node available), so their operations fail — this is the safe behavior.
- After the partition heals, the isolated node catches up via read repair (inconsistencies detected during reads) and anti-entropy repair (Merkle tree comparison). If neither runs promptly, the node may serve stale data.