Tier 1 — Building Block
1. What Is It?
A is a copy of a primary (leader) database that receives a continuous stream of changes from the primary and can serve read queries. The primary handles all writes; replicas handle reads. This is also called read/write separation or leader-follower .
Without read replicas, a single database node handles both writes (which require durable commits and locking) and reads (which scan indexes and return results). At scale, these workloads compete for the same CPU, memory, and I/O budget. Read replicas separate these concerns: writes go to the primary, reads are distributed across one or more replicas, multiplying read horizontally.
The tradeoff is lag: replicas receive changes asynchronously (usually), meaning they may lag the primary by milliseconds to seconds. Reads from replicas can return stale data.
Separate writes from reads
The primary handles writes and streams changes to replicas that serve reads, but reads from a lagging async replica can be stale.
The write client sends an insert to the primary, which handles all writes.
Text version
- The write client sends an insert to the primary, which handles all writes.
- The change streams out, but Replica 2 has not applied it.
- Replica 1 applies the change so its reads include the new data.
- The read load balancer spreads queries across replicas, adding read capacity.
- Replica 2 still lags behind the primary when this read arrives.
- Replica 2 returns stale data before the delayed change arrives.
Your e-commerce platform is experiencing performance degradation because product catalog browsing (reads) and order processing (writes) are competing for the same database resources. Which of the following best describes why adding read replicas would help this specific situation?
2. How It Works
Replication Mechanism
- Primary receives a write (INSERT, UPDATE, DELETE).
- Primary writes the change to its Write-Ahead Log () (PostgreSQL) or binlog (MySQL) before committing.
- A stream ships /binlog entries to each replica in near-real-time.
- Each replica applies the log entries to its own data files, staying in sync with the primary.
Read/Write Routing
The application (or a proxy like PgBouncer, ProxySQL, RDS Proxy) must route queries to the correct endpoint:
INSERT/UPDATE/DELETE/BEGIN TRANSACTION→ Primary connection stringSELECT(that tolerates stale data) → ReplicaSELECT(immediately after a write, must be fresh) → Primary, or use read-your-writes consistency technique
Replication Modes
- Asynchronous (default in MySQL, PostgreSQL): Primary commits immediately; WAL is sent to replicas without waiting for acknowledgment. Fastest writes; small lag window (~10ms–1s typically, can be longer under load).
- Synchronous: Primary waits for at least one replica to durably persist the change — and, in the strictest mode (PostgreSQL
synchronous_commit = remote_apply), to apply it so it is visible to queries on that replica — before committing. Zero data loss; higher write (~+10ms RTT per synchronous replica). - Semi-synchronous (MySQL): Primary waits only for at least one replica to receive the entry into its relay log (not apply it) before committing. Balances and .
Route fresh reads to the primary
The router sends writes and immediate fresh reads to the primary, while reads that tolerate stale data can use a replica.
The app sends the router an insert for user forty-two’s order.
Text version
- The app sends the router an insert for user forty-two’s order.
- The router sends this write to the primary, because replicas are read-only.
- An immediate read also goes to the primary because a replica may not have the new row.
- The primary returns the new order row, so the user sees their own write.
- The request for twenty popular products can tolerate stale data, so it goes to a replica.
- The replica returns results that may lag the primary by about fifty milliseconds.
A user submits a checkout form that creates a new order, and the very next request immediately fetches that order to display a confirmation page. Your backend routes all SELECT queries to a read replica by default. What problem could arise, and how should it be handled?
3. Variants & Comparisons
| Configuration | Consistency | Write Latency | Read Scalability | Failure Behavior |
|---|---|---|---|---|
| Single Primary, No Replicas | Strong | Fast | Limited to one node | Primary down = full outage |
| Async Replicas | Eventual (lag: 10ms–1s) | Fast (no wait) | Scales horizontally | Replica down = reads to others; primary down = possible data loss if async replica promoted |
| Sync Replica (1 standby) | Strong on the standby only with remote_apply (else standby reads can lag) | +RTT latency per write | One additional read node | No data loss on failover to synced standby |
| Multi-Region Replicas | Eventual (lag: 50ms–500ms) | Fast locally | Global read distribution | Serves reads during regional outage; writes fail if primary region is down |
| Multi-Primary (Multi-Master) | Eventual (conflict resolution required) | Fast | Reads scale; writes only partly (every node applies every write) | Complex conflict resolution; risk of split-brain |
Specific Technologies:
- PostgreSQL Streaming : Native async/sync physical . -level replication. Exact byte-for-byte copy of primary. Managed versions: AWS RDS/Aurora (Aurora replicas have ~10ms lag), GCP Cloud SQL, Azure Database.
- MySQL Group Replication / InnoDB Cluster: Paxos-based replication (a majority agrees on each transaction's order before commit), supports automatic failover. Used by MySQL Router for read/write splitting.
- AWS Aurora: Custom replication protocol with shared storage layer. Up to 15 read replicas with <10ms lag. Failover in ~30 seconds. Aurora Global Database for cross-region replicas (60ms+ lag typical).
- Vitess (YouTube/PlanetScale): + replication management layer for MySQL. Used by YouTube, Slack, GitHub. Handles read/write routing and pooling at massive scale.
- PgBouncer / ProxySQL: Connection poolers that also route queries — ProxySQL can automatically send writes to primary and reads to replicas using query analysis rules.
Compare database configurations
Async replicas scale reads but risk lost writes on promotion; a surviving sync replica preserves acknowledged commits.
Async replicas apply changes after the primary commits, so their reads can be stale.
Text version
- Async replicas apply changes after the primary commits, so their reads can be stale.
- Sync commits wait for a replica’s durable acknowledgment, adding latency.
- Replicas add read capacity because each readable copy serves queries independently.
- Promoting an async replica can lose writes that it never received from the primary.
- Async replicas keep writes fast and scale reads, but lag means those reads can be stale.
Your team is deploying a write-heavy e-commerce platform globally. Stakeholders want users in Europe and Asia to experience fast reads, and the engineering team is comfortable accepting some read staleness. However, if the primary region goes down, the business can tolerate a brief window where writes fail — but reads must continue being served. Which replication configuration best fits these requirements?
4. When to Use It (and When NOT To)
Use Read Replicas When:
- Read-to-write ratio > 5:1: Most web apps are read-heavy (product listings, profile pages, feed queries)
- Primary DB CPU > 60% from reads: Reads are starving write
- Analytics/reporting queries: Long-running
SELECTscans can block or compete with OLTP; route them to a dedicated reporting replica - Geographic distribution: Put a replica in each region to serve local reads with low (e.g., US replica for US users, EU replica for EU users)
- : A synchronous standby replica means zero data loss on primary failure
Decision triggers:
- "If your read QPS > 70% of DB capacity → add read replicas"
- "If you have reporting workloads running on the same DB as OLTP → add a dedicated analytics replica"
- "If you need <10ms reads from multiple geographies → add regional replicas"
Do NOT Use Read Replicas When:
- Strong read-after-write consistency required: After writing a record, user immediately reads it — if routed to a replica, they may see stale data. Fix: route such reads to primary, or use a sync replica with
synchronous_commit = remote_apply(PostgreSQL). - lag is unacceptable: Financial balances, inventory counts during checkout — even 100ms stale data causes correctness issues. Use primary for these reads.
- Write-heavy workload: Replicas help with reads; if your bottleneck is write , you need , not replicas.
Anti-patterns:
- Reading from replica immediately after write without a read-your-writes mechanism — users see their own write disappear.
- Ignoring lag — lag can grow under write spikes; replica may fall significantly behind without .
- Using replicas for distributed transactions — transactions that span primary + replica are not atomic.
An e-commerce platform processes orders at checkout. When a user adds an item to their cart, the inventory count is immediately decremented in the database. The checkout service then reads the inventory count to verify stock availability before confirming the order. The team is considering routing these inventory reads to a read replica to reduce load on the primary database. Why is this a poor choice?
5. Real-World Usage
GitHub (MySQL with Vitess): GitHub serves ~100M read queries/day from MySQL read replicas. They use ProxySQL to route reads to replicas and writes to the primary. A critical pattern they document: "read-your-writes" is implemented by recording the binlog position after each write; subsequent reads are directed to the primary until the replica reports it has caught up to that position.
Instagram (PostgreSQL + Django): Instagram used Django's multiple database routing to direct reads to PostgreSQL replicas. Their 2012 engineering blog describes scaling to ~25M users with a primary + 2 async replicas per shard, routing 90% of reads to replicas. lag was acceptable because most reads (photo feeds, profile views) tolerate .
AWS Aurora Multi-AZ: Aurora maintains one primary and up to 15 replicas using a shared distributed storage layer (not traditional shipping). Because all replicas read from the same storage layer, lag is <10ms — much lower than traditional async replication. This is how Aurora achieves "fast local reads with replica consistency."
A user posts a new comment on your platform, which is backed by a primary database and several async read replicas. Immediately after posting, the user is redirected to a page that reads their own comment back from the database. To avoid showing the user a 'missing' comment due to replication lag, which strategy should your system use?
6. Interview Cheat Sheet
Key sentences to demonstrate depth:
- "Read replicas multiply read horizontally — each replica is an independent read node, so N replicas give you N× read capacity."
- "The fundamental tradeoff is lag: async replicas are ~10ms–1s behind the primary. For most reads (feed queries, product listings, profile views), this is acceptable. For reads immediately after writes, I route to the primary."
- " lag can become a serious problem under write bursts — if the primary is writing 50K rows/sec and a replica falls behind, it could be minutes behind. You need lag and ."
- "A synchronous standby replica costs you write (must wait for replica ACK) but gives you zero data loss on failover — worth it for financial or critical data."
- "Read replicas solve read , not write throughput. If writes are the bottleneck, I need — replicas don't help there."
Common follow-up questions:
| Question | Concise Answer |
|---|---|
| "What is replication lag?" | The time between when the primary commits a write and when a replica has applied it. Typically 10ms–100ms async; can grow to minutes under write spikes. |
| "How do you handle read-your-writes?" | Option 1: Route all reads immediately after a write to the primary. Option 2: Track replication position (LSN/GTID) after each write; route reads to replica only when replica has caught up. |
| "What happens when the primary fails?" | A replica must be promoted to primary (manual or automatic via tools like Patroni, MHA, AWS RDS Multi-AZ). With async replication, any un-replicated writes may be lost. |
| "How do you avoid replica lag growing?" | Monitor replica lag metric; set alerting threshold (e.g., >5s = page). Reduce write throughput or add more powerful replicas. Consider sync replication for critical data. |
| "Why not just shard instead of using replicas?" | Sharding adds significant complexity (cross-shard queries, distributed transactions, shard key choice). Replicas are simpler — use them first; shard when writes become the bottleneck. |
Connections to other building blocks:
- Caching Strategies: Complementary to caching. Cache handles repeated reads of the same objects; replicas scale diverse query patterns. Use both: cache for hot keys, replicas for query load.
- & : Read replicas scale read throughput; sharding scales write throughput. A fully scaled system often uses both: shards, each shard having replicas.
- Write-Ahead Log (): Replication is fundamentally built on the . The replica is a consumer of the primary's WAL stream.
- CAP Theorem: Async replicas = AP (, ). Sync replicas with = CP (, lower under network partition).
- Load Balancing: The read in front of replicas distributes read traffic; it needs health checking to avoid routing to a lagged or failed replica.