DATABASE LAB · SEND · FLUSH · REPLAY

Replication lag: WAL positions and delayed feedback

Trace individual records and separate byte backlog, unapplied-record age and delayed feedback.

One primary · one standby · fixed-size teaching records

Exact replication evidence

Inspect positions, queues and every record timestamp

Follow one record through distinct boundaries

Each generated record occupies one hundred synthetic bytes and is assumed locally durable immediately. It must be sent, arrive and be written on the standby, be flushed there, then be replayed before its change is visible in the standby database. Replay feedback takes at least two additional ticks to reach the primary. The six bars show the highest contiguous byte position at each boundary. Inspect record selects a stable identifier and displays its actual timestamps, so the diagram can be checked against individual events instead of treating all replication as one subtraction.

Control production and downstream capacity

WAL records generated per tick sets demand. Generate until tick is exclusive: fifteen produces records on ticks zero through fourteen. Records sent per tick limits the network sender, while Forward network delay postpones arrival of sent records. Records flushed per tick limits standby durability progress, and Records replayed per tick limits applying durable records. Zero disables the corresponding activity. Each setting rebuilds a fresh finite run. The event order within a tick is generation, send, arrival/write, flush, replay, then feedback. With zero forward delay and sufficient capacity, several boundaries can share a timestamp; this is a discrete teaching assumption, not a disk latency measurement.

Isolate network and replay stalls

Pause network during ticks 8–15 blocks new sends, arrivals and returning feedback in that fixed inclusive interval. Already sent records are retained in transit and released in order after the pause; there is no modeled loss or retry protocol. Flush and replay can continue consuming previously received records. Pause replay during ticks 8–15 blocks applying records but does not stop sends, writes or flushes. Compare the bars and queues to identify the bottleneck. A growing flushed-minus-replayed gap points at application progress in this fixture, while a growing primary-minus-sent gap points at insufficient sending capacity.

Try backlog, catch-up and a missing feedback sample

Restore defaults: generate three records per tick for fifteen ticks, send and flush four, replay one, and use a forward delay of two. At tick fifteen, the primary position is 4500 bytes and replay is 1400 bytes. At tick thirty, replay reaches 2900 bytes even though generation has already stopped. Increase replay capacity to four and compare the same timestamps. Set flush capacity to zero: written data accumulates but nothing can be replayed. Now use one generated record, one tick of generation, zero network delay and capacities of one. At tick zero the record is replayed with no backlog, but feedback is still absent. At tick two, the reported delay is two ticks even though the byte backlog is zero.

Do not confuse three different quantities

Byte backlog is primary position minus replay position. Oldest unreplayed age measures how long the earliest unapplied record has existed; it is absent when no record is pending. Last reported delay measures local durability to receipt of replay feedback for the latest acknowledged record. It is not an estimate of future catch-up time. This fixture expires that last sample after five ticks without new generation or new feedback once fully reported and caught up. That chosen five-tick policy is not PostgreSQL’s internal reporting interval. Read unavailable as missing evidence, not automatically as zero delay.

Inspect the finite run and its assumptions

Play reveals sixty model ticks over sixty inspection seconds. Pause holds the state, Next tick advances one tick, Restart rewinds, Speed changes viewing pace and Inspect time scrubs. Restore defaults resets the scenario; Inspect record changes only the selected evidence. Records not generated at the selected tick are reported as not yet present. The run stops at tick sixty even if work remains. It has one primary and one standby, equal record sizes, no transaction boundaries, no disk failures, no retention limit, no promotion and no synchronous-commit policy. LSNs are simplified integer byte offsets, not actual PostgreSQL WAL addresses. All state stays inside the browser; no database or network connection is opened.

Metric reference: PostgreSQL replication statistics documentation.

Views are my own and do not represent any employer, past or present.

Search