skip to content

questions

20

What is replication lag between a primary database and its replica, and in what two units is it normally measured?

level: juniorimportance: must knowfreq 66%

answer

  1. Distance between primary's newest change and replica's applied change
  2. Two units: bytes (log position) and seconds (staleness)
  3. Received ≠ applied — quote lag at the applied position
  4. Idle primary makes seconds-lag lie; bytes stay honest
  5. Heartbeat row gives truthful time lag

basics

~20 s

Replication lag is how far a replica trails its primary. It is measured in bytes — how much of the primary's change log the replica has not consumed yet — and in seconds — how old the newest change the replica has applied is.

solid answer

~60 s

A replica is kept current by streaming the primary's change log (WAL in PostgreSQL, binlog in MySQL) and replaying it. **Replication lag is the distance between the primary's newest change and the last change the replica has durably applied.** Two units are used, and they answer different questions: - **Bytes (or log positions)** — the difference between the primary's current log position and the replica's applied position. This is a direct volume measure: how much work the replica still owes. Good for spotting growth trends and for retention safety (falling too far behind can push the replica off the primary's retained log). - **Seconds (time)** — how stale the data on the replica is: the wall-clock age of the newest change it has applied. This is what product requirements are written in ("reports may be up to 5 seconds stale") and what an RPO estimate uses. They are not interchangeable. A megabyte behind is seconds on a fast replica and minutes on an overloaded one; a system with no writes has zero seconds of lag no matter what. Production monitoring tracks both.

go deeper

for a junior

Define it clearly — the replica trails the primary because changes travel through a log and must be replayed — and name both units, bytes and seconds.

for a middle

Add that lag exists per pipeline stage (sent, received, flushed, applied) and that the applied position is the one that matters to a reader.

for a senior

Emphasise that the two units fail in different ways, that a heartbeat row is how you get truthful time lag, and that trend matters more than a spike.

for a principal

Frame lag as two separate budgets — a staleness budget for read traffic and a recovery-point budget for failover — and note that log retention turns extreme lag into a rebuild rather than a catch-up.

## The mechanism that creates lag A relational engine writes every change into an ordered, append-only log before (or as) it changes data pages: the **write-ahead log (WAL)** in PostgreSQL, the **binary log (binlog)** in MySQL. Replication reuses that log. The primary streams log records to the replica; the replica receives them, writes them to its own disk, and then **applies** (replays) them so its copy of the data catches up. Every one of those steps costs time, so a replica is always at least slightly behind. **Replication lag is that distance.** It only reaches zero momentarily, when the replica has applied everything the primary has produced so far. Note the ordering: *received* is not *applied*. A replica can hold ten seconds of change records on its disk and still be serving reads from data that is ten seconds old, because the apply step has not caught up. Lag is normally quoted against the **applied** position, since that is what a query on the replica can actually see. ## Unit 1: bytes / log position Log positions are monotonically increasing offsets — PostgreSQL calls them LSNs (log sequence numbers), MySQL uses file plus offset. Subtracting the replica's position from the primary's current position gives a **byte distance**: how much change data the replica still owes. Why this unit matters: - **It is honest when the system is idle.** If nobody writes for an hour, byte lag is zero because there is genuinely nothing outstanding. - **It measures backlog volume**, which is what predicts recovery time and what threatens log retention. If the primary keeps only, say, the last few gigabytes of log (or a replication slot is retaining log on the replica's behalf), byte lag tells you how close you are to either losing the replica entirely (it must be rebuilt from a fresh copy) or filling the primary's disk. - **It is comparable across replicas** fed from the same primary. What it does not tell you: how stale the data *feels*. Ten megabytes of small OLTP transactions and ten megabytes from one bulk load are very different amounts of staleness. ## Unit 2: seconds / time behind Time lag answers "how old is the newest data visible on this replica?" It is usually derived from the timestamp embedded in the change record the replica most recently applied, compared against now. Why this unit matters: - **Product and SLA language is in seconds.** "The dashboard may lag by up to 5 seconds" is a staleness budget; "we can lose at most 1 second of writes on failover" is a recovery point objective. Both are time statements. - **It is directly actionable** — an operator can decide to drain read traffic away from a replica whose data is a minute old. Its weaknesses are the mirror image of the byte metric. **On an idle primary, time lag collapses to zero or becomes undefined even if the replication link is broken**, because the replica has applied everything it has ever been sent and there is no newer timestamp to compare against. It is also sensitive to clock differences between machines and to how the engine computes it (in a chained setup, timestamps originate from the top-level primary, not the intermediate node). ## Why both, always Mature monitoring records both units side by side because their failure modes do not overlap: | Situation | Byte lag | Time lag | |---|---|---| | Healthy, busy system | small, stable | small, stable | | Replica apply is too slow | grows steadily | grows steadily | | Write burst, replica keeps up | spikes then drains | barely moves | | Primary idle, link broken | grows only when writes resume | reads ~0 — misleading | | Bulk load / index build | large | may stay small | A common practical addition is a **heartbeat**: a tiny row on the primary updated with the current timestamp every second. The replica reads that row and subtracts it from its own clock. Because a write is always flowing, the heartbeat gives a truthful time-lag number even on an otherwise idle system, and it detects a dead replication link instead of reporting zero. ## What normal looks like On a healthy asynchronous replica on the same network, lag is typically single-digit to low-hundreds of milliseconds, with brief spikes during checkpoints, bulk writes, or schema changes. The signal that matters is not a spike but a **trend**: lag that keeps climbing means the replica's apply throughput is lower than the primary's write throughput, and it will not recover on its own until the write rate drops or the replica gets faster.

  • Why can byte lag and time lag disagree sharply during a bulk data load?
    A bulk load produces an enormous volume of change-log records in a very short window, so byte lag spikes into gigabytes. But those records all carry near-identical, very recent timestamps, so as long as the replica is chewing through them steadily the newest applied record is only a second or two old and time lag stays small. The reverse also happens: a single long, slow statement can produce few bytes but hold the applied timestamp far back.
  • If a replica reports zero seconds behind, can you conclude replication is healthy?
    No. Time-based lag on most engines is computed from the change record currently being applied, so when there is nothing to apply — because the primary is idle, or because the receiving side is disconnected and no new records are arriving — the metric reads zero or null. You need the byte distance from the primary's own view of the connection, plus a heartbeat and a connection-liveness check, before calling replication healthy.

Think of a scribe copying a stack of dictated notes. Byte lag is the height of the pile still waiting on the desk; time lag is how old the newest note the scribe has finished actually is. If the speaker stops talking, the pile empties and the scribe looks caught up — even if the courier bringing new notes died an hour ago.

saying these in an interview costs you the question

  • Saying lag is one number, without distinguishing received/written from applied
  • Treating seconds-behind as trustworthy on a low-write or idle system
  • Assuming lag zero means the replica is a synchronous copy — asynchronous replicas are simply momentarily caught up
  • Claiming lag is purely a network problem, ignoring apply-side cost
  • Believing lag self-corrects; sustained lag means apply throughput is below write throughput

context

open as a page

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%

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.

open as a page

What is the difference between synchronous and asynchronous replication in a relational database, and what does each mean for data loss if the primary dies suddenly?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Asynchronous: the primary confirms the commit as soon as it is durable locally and ships the change afterwards, so a sudden primary loss can lose recently committed transactions. Synchronous: the primary waits for a standby to acknowledge before confirming, so no acknowledged transaction is lost, at the cost of extra latency on every commit.

open as a page

Replication from a primary to a replica happens in several stages. Which stages can lag independently, and what do PostgreSQL's pg_stat_replication view and MySQL's Seconds_Behind_Source field each tell you about them?

level: middleimportance: must knowfreq 56%

basics

~20 s

Stages: the primary generates log records, sends them, the replica writes them, flushes them to disk, then replays them. pg_stat_replication exposes sent/write/flush/replay positions and the matching lag intervals per stage. MySQL's Seconds_Behind_Source covers only the apply stage — receive lag is separate.

open as a page

Explain the difference between physical (block/WAL-shipping) replication and logical (row-level) replication between relational databases, and what each produces on the receiving side.

level: middleimportance: must knowfreq 56%

basics

~20 s

Physical replication ships the low-level change log describing byte and page edits, so the replica is a block-for-block clone — same version, all objects, read-only. Logical replication decodes changes into row-level events (insert/update/delete with column values) that the target executes, so it can differ in version, schema and contents.

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

When a system is described as synchronously replicated, the acknowledgement may mean the standby received the change, flushed it to its own log, or replayed it so queries can see it. Why does that distinction matter, and what does each level buy you?

level: middleimportance: must knowfreq 50%

basics

~20 s

Each level survives a different failure. Received in memory survives losing only the primary; flushed to the standby's disk also survives the standby restarting; replayed additionally makes the change visible to readers on the standby. Later levels add latency, so pick the earliest level that covers the failure you care about.

open as a page

A read replica repeatedly falls minutes behind its primary during peak hours, even though the replication network link is nowhere near saturated. What are the usual causes of apply-side replication lag, and how would you narrow it down?

level: seniorimportance: must knowfreq 52%

basics

~20 s

Usual causes: apply is far less parallel than the primary's concurrent writers; long or huge transactions arriving as one burst; row changes on the replica lacking a usable index so each change scans; replica hardware or I/O weaker; and replay blocked by conflicting long-running queries on the replica. Narrow it down by finding which stage and which transaction stalls.

open as a page

What are the practical limitations and operational risks of running row-level logical replication compared with block/WAL-level physical replication?

level: seniorimportance: must knowfreq 41%

basics

~20 s

Logical replication does not carry schema changes, sequence values, or (by default) everything the cluster contains; apply is far slower per change; the writable target can hit conflicts that stall the whole subscription; the initial snapshot is expensive; and an unconsumed change stream retains log on the source until its disk fills.

open as a page

Your database primary's commits suddenly hang for every client, and the only change in the environment is that one standby became unreachable. Explain the mechanism, and how you would configure the system so that losing a standby cannot stall writes.

level: seniorimportance: must knowfreq 44%

basics

~20 s

Synchronous commit makes the primary wait for a standby's acknowledgement before returning; with the only such standby gone, every commit waits forever. Fixes: use a quorum of any k of n with n greater than k, configure an automatic timeout that degrades to asynchronous, and monitor and alert on degraded mode.

open as a page

You need to feed a separate reporting database with just three tables out of a 400-table production database. The reporting database must also hold its own locally-created summary tables and extra indexes tuned for analysts. Would you use physical or logical replication, and what does that choice commit you to?

level: middleimportance: should knowfreq 42%

basics

~20 s

Logical replication. Physical copies the entire cluster byte-for-byte and keeps the target read-only, so neither selective tables nor local tables and extra indexes are possible. Logical costs you: manual DDL coordination, row identity on the three tables, conflict handling, and slot/log retention on the source.

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

Time-based replication-lag metrics can report zero or null while a replica is genuinely far behind. Why does that happen, and how would you measure lag so the number is trustworthy?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Time-based lag is derived from the newest change record the replica applied. With no new records — an idle primary, or a dead receiver whose backlog has drained — there is nothing to compare against, so it reads zero or null. Trustworthy measurement combines byte distance from the primary, thread/connection state, and a heartbeat write.

open as a page

In row-level logical replication, how does the receiving database find the row to change when it receives an UPDATE or DELETE event, and what goes wrong when the source table has no primary key?

level: seniorimportance: should knowfreq 37%

basics

~20 s

The change event carries an identifying value set — the row's replica identity, by default its primary key — and the receiver looks the row up by it. With no primary key, either the operation is rejected outright, or the full old row must be logged and matched column-by-column, forcing a scan per event and collapsing throughput.

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

With three or more standbys, how does quorum-based synchronous commit (waiting for any k of n acknowledgements) differ from naming a single synchronous standby, and what does it change for durability and availability?

level: seniorimportance: should knowfreq 36%

basics

~20 s

With one named synchronous standby, that standby is a single point of failure for writes and the only node guaranteed to hold every acknowledged commit. Quorum commit waits for any k of n standbys, so any n minus k can be slow or dead without blocking writes, and commit latency follows the k-th fastest rather than one fixed node.

open as a page

How would you choose replication-lag alerting thresholds for a fleet of read replicas, and what should happen automatically when a replica exceeds them?

level: principalimportance: should knowfreq 33%

basics

~20 s

Derive thresholds from what each replica is for: a staleness budget in seconds for read traffic, a recovery-point budget for failover candidates, and a hard byte threshold from log retention. Alert on sustained growth, not single spikes. Above the staleness budget, drain the replica from the read pool automatically, with hysteresis before re-adding.

open as a page

How do you decide whether a system genuinely needs zero-data-loss replication given its latency and availability costs, and what would you configure differently for a payments ledger versus a clickstream ingestion pipeline?

level: principalimportance: should knowfreq 32%

basics

~20 s

Decide from the cost of losing the last second of writes and whether they can be reconstructed upstream. A ledger cannot reconstruct them, so it pays a same-region synchronous quorum plus asynchronous cross-region copies. Clickstream data is replayable from the producer, so asynchronous replication and relaxed local commit are the right trade.

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

How does row-level logical replication make a near-zero-downtime major-version upgrade of a relational database possible, and why can block/WAL-level physical replication not be used for the same purpose?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Logical replication ships decoded row changes, which a target on a newer major version can apply as ordinary writes — so you build the new-version database alongside, let it catch up, and cut over in seconds. Physical replication replays version-specific page-level records, so both nodes must run the identical major version.

open as a page