skip to content

questions

5

What is a read replica in a relational database, and how do you decide which of your application's reads are safe to send to one instead of to the primary?

level: juniorimportance: must knowfreq 68%

answer

  1. read-only copy, applies primary's change stream
  2. stale by an unbounded, usually tiny, amount
  3. safe: reports, listings, exports
  4. unsafe: read-modify-write, guard reads, post-submit page
  5. tag per read path, fall back on lag

basics

~20 s

A read replica is a read-only copy that continuously applies the primary's change stream, so it trails the primary slightly. Send it reads that tolerate slightly old data (listings, reports, exports). Keep writes, and any read that must reflect a just-made write, on the primary.

solid answer

~50 s

A read replica is a second copy of the database that continuously receives and applies the primary's changes and accepts only reads. Because the usual setup acknowledges the client's commit before the replica has applied it, a replica answers with the primary's state from some moment in the recent past: normally milliseconds behind, sometimes much more. Routing is therefore decided by tolerance, not by volume. A read is replica-safe when a slightly old answer is merely out of date rather than wrong: reporting, analytics, search and listing pages, feeds, background exports. Unsafe reads are read-modify-write flows (SELECT then UPDATE of the same rows), uniqueness or balance checks that gate a write, any read inside a read-write transaction, and the page a user sees right after submitting a change. In practice you tag read paths individually rather than flipping one global switch, and you fall back to the primary when a replica's lag crosses a threshold.

go deeper

for a junior

Define read replica, say it is read-only and slightly behind, and give two safe reads and two unsafe reads with reasons.

for a middle

Add how routing is implemented (separate pools or a reader endpoint, per read path) and why read-modify-write and guard reads must stay on the primary.

for a senior

Talk about lag-aware fallback, taking a lagging replica out of rotation, and the feedback loop where heavy replica queries slow the replica's own apply.

for a principal

Frame it as a staleness budget per read path with an explicit SLO, plus capacity reality: replicas buy read throughput and a failover target, never write throughput.

## What a read replica is A read replica is a second database instance that continuously consumes the primary's stream of changes and applies them to its own copy of the data. It accepts client connections but only read statements; writes are rejected, because its contents must stay a pure consequence of the primary's change stream. The primary remains the single node that accepts writes. ## Why a replica is behind In the common configuration the primary does not wait for the replica before telling the client the transaction is committed. It makes the change durable locally, answers the client, and ships the change record onward. The replica receives it and applies it some time later. That interval is normally a few milliseconds, but it is not bounded: write bursts, a saturated replica, a slow network link, or a long-running query on the replica can stretch it to seconds or minutes. So the correct mental model is not the replica is current, it is the replica shows the primary as of some recent, unspecified moment. ## Reads that are safe to offload A read is replica-safe when the worst outcome of an old answer is that the user sees something slightly out of date: - Reporting, dashboards, aggregate counts, BI-style queries. - Catalogue, search, and listing pages where the item set changes slowly. - Feeds, recommendations, and other best-effort content. - Bulk exports, ETL extraction, and other batch scans, which also keeps their I/O off the primary. ## Reads that must stay on the primary - Read-modify-write: you SELECT a row, compute something, then UPDATE it. Reading a stale version and writing based on it silently corrupts data, and the row locks that would protect you exist only on the primary. - Guard reads: checking whether an email is already taken, whether a balance covers a debit, whether a booking slot is free. The check is only meaningful against the state the write will be applied to. - Anything in the same read-write transaction. A single transaction lives on one connection to one node; you cannot split it. - Read-after-write on the user's own action: the page rendered right after a submit. ## How routing is implemented Three common layers. Application-level: two connection pools (writer, reader) and an explicit choice per query or per request handler, often expressed as a read-only annotation on the service method. Driver or framework level: read-write splitting where read-only transactions are steered to a reader pool automatically. Proxy level: a connection pooler or middleware parses the statement or reads a routing hint and picks a backend. Managed cloud databases usually expose two endpoints, a writer endpoint and a reader endpoint that load-balances across replicas. Whichever layer you use, the decision must be per read path. Turning on a blanket send all SELECTs to replicas switch is how read-after-write bugs get into production, because it also redirects the guard reads. ## Two practical cautions First, replicas do not scale writes. Every replica applies the full write stream, so a write-heavy system gets no relief from adding replicas, and each new replica adds shipping cost on the primary. Second, offloading is not free of feedback: heavy analytical queries on a replica can slow its apply of the change stream, which makes the replica staler for everyone reading it. That is why a lag-aware fallback matters: if a replica is more than N seconds behind, take it out of rotation or send its traffic to the primary. ## What interviewers listen for That you say read-only rather than fast, that you name the async acknowledgement as the reason staleness exists, that you can classify concrete reads into safe and unsafe with a reason, and that you know a replica is also a hot standby for failover, not merely a query offload target.

  • Does adding read replicas help a write-heavy workload?
    Almost never. Every replica must apply the entire write stream, so replicas add read capacity only. A write-bound primary is relieved by write batching, schema and index changes, partitioning, or sharding, not by more replicas. Replicas can even add load on the primary, since it must ship the change stream to each of them.
  • Can a single database transaction read from a replica and write to the primary?
    No. A transaction is bound to one connection to one node, so its reads and writes happen on the same server. You can run two separate transactions, a read-only one on a replica and a write on the primary, but then you lose the atomic snapshot and the row locks that made the read meaningful for the write.

A replica is a photocopy that a clerk keeps re-copying as pages change: fine for reading yesterday's numbers, useless for checking whether the seat you are about to book is still free.

saying these in an interview costs you the question

  • Saying replicas are used because they are faster, rather than because they add read capacity for staleness-tolerant reads
  • Routing every SELECT to replicas globally, including checks that gate writes
  • Claiming replicas relieve write load
  • Assuming a replica is always at most a fixed number of milliseconds behind
  • Proposing to write to a replica and let it sync back to the primary

context

open as a page

A user saves their profile, the application immediately re-reads it from an asynchronous read replica, and the old values come back. Explain why this happens and what the standard fixes are.

level: middleimportance: must knowfreq 60%

basics

~20 s

The primary acknowledged the commit before the replica applied it, so the follow-up read hit a copy that does not yet contain the change. Fixes: read that user's data from the primary for a short window after their write, or make the read wait until the replica has applied that write's position.

open as a page

Beyond simply returning older rows, what user-visible anomalies appear when an application spreads its reads over a pool of asynchronous replicas, and how do you prevent them?

level: middleimportance: should knowfreq 44%

basics

~20 s

Different replicas are at different positions, so a user can see time go backwards between two requests, see an effect without its cause, or get inconsistent halves of one page. Prevent it by pinning a session (or a page render) to one replica, and by ejecting replicas whose lag exceeds a threshold.

open as a page

Instead of pinning a user to the primary for a fixed window after they write, how can an application make a replica read wait until that replica has applied that specific write, using a replication position such as a PostgreSQL LSN or a MySQL GTID?

level: seniorimportance: should knowfreq 36%

basics

~20 s

After committing, read the write's position in the change stream (an LSN or GTID) and carry it with the session or request. Before serving a read, compare it with the replica's applied position: if the replica is behind, wait briefly for it to catch up, or fall back to the primary.

open as a page

What is a deliberately delayed replica, one configured to stay (say) one hour behind the primary, and which failure does it protect against that a normal standby and a nightly backup do not?

level: seniorimportance: nice to knowfreq 26%

basics

~20 s

A delayed replica receives the change stream immediately but deliberately withholds applying it for a fixed interval, so it holds a live copy of the database as it was an hour ago. That gives you a fast rewind after a destructive human or application error, which normal standbys replicate instantly.

open as a page