Skip to content

Research notes / Replication contracts

Replication acknowledgements: received, durable, applied

Published 12 October 2026 / Primary-source review

A replica can receive a change before it becomes durable, and persist it before queries can observe it. A successful acknowledgement protects only the boundary and replica set required by the actual configuration.

Start with the completion contract

SNIA Swordfish distinguishes the maintained-copy relationship, called a mirror, from its update mode. The existence of another copy does not specify how writes complete or promise instantaneous failover. [8] Ask which event releases the caller, which replicas participate and which failures the storage stack can survive.

PostgreSQL 18 is a concrete example, not a universal replication vocabulary. The following table assumes normal durable local WAL handling and configured synchronous standbys. It concerns the transaction commit record, not a requirement to flush every modified data page.

PostgreSQL 18 synchronous_commit: required progress before success. Sources [1] and [2].
SettingLocal WAL durable?Required remote progress
offNot required before successNone
localYesNone
remote_writeYesCommit record written to standby filesystem
onYesCommit record flushed to durable standby storage
remote_applyYesCommit record durable and transaction replayed

A standby filesystem write can survive a database-process crash without surviving an operating-system crash. Durable WAL does not yet imply that a standby query sees the transaction; remote_apply adds replay. These guarantees depend on the underlying durability configuration and storage behaving as promised. [1]

Replay does not refresh an older read snapshot

Operational inference: after a remote_apply acknowledgement, route the read to a standby whose replay was actually required and use a sufficiently new read snapshot. PostgreSQL Repeatable Read retains the snapshot established by the first non-transaction-control statement. An already-running transaction can therefore keep seeing an earlier version even after the standby has applied the update. Replay progress and snapshot isolation answer different questions. [1] [10]

The replica set matters as much as the setting

An empty synchronous_standby_names means no remote wait, even with synchronous_commit=on. FIRST n (...) selects by priority; ANY n (...) accepts the required count of acknowledgements among the named candidates. Neither means every replica, and the names are standby application names, not necessarily hostnames. [2]

Streaming replication defaults to asynchronous operation. A promoted standby can lack acknowledged transactions; required synchronous standbys can instead delay completion when unavailable. PostgreSQL 18 cascading replication remains asynchronous. Protection of a directly connected standby therefore does not automatically extend to its downstream replicas. [3]

Operational inference: a claim of zero recovery-point loss needs an explicit failure scenario, surviving acknowledged replica and promotion rule. Replica count alone is insufficient. Preventing an old primary from continuing to write is a separate fencing problem.

The same label can hide a different boundary

DRBD replicates block-device writes. Its protocol A completes after local disk completion and placement in the local TCP send buffer; B also waits for peer receipt; C waits for confirmed local and remote disk writes. LINBIT calls B memory-synchronous or semi-synchronous. [6, section 2.3]

Do not equate DRBD B with PostgreSQL remote_write: peer receipt and a filesystem write are distinct events. Nor does DRBD C establish SQL query visibility. This is a comparison of documented boundaries, not a performance ranking.

Asynchronous does not mean unable to block: DRBD protocol A can stall the writer when its send buffer fills. Removing a remote acknowledgement from completion does not remove finite buffering or bandwidth limits. [6, section 2.18]

Chain replication puts the reply boundary at the tail

Van Renesse and Schneider's OSDI 2004 protocol sends updates to a head, forwards changes through an ordered chain, and serves queries and replies at its tail. This is not majority voting for each data update; a separate master reconfigures membership. The model assumes fail-stop servers and reliable FIFO links. Its prototype uses Paxos for the master. [11, sections 3 and 3.1]

Do not read that proof as a PostgreSQL cascade guarantee: the protocols differ. The paper's simulated throughput is not a modern hardware benchmark, and it does not promise service across arbitrary network partitions. [11, sections 5 and 6] See the chain replication record.

Lag needs a stage, unit and observation context

PostgreSQL's pg_stat_replication reports directly connected standbys. Its sent, written, flushed and replayed LSN positions distinguish progress stages. The lag intervals include recent processing and notification delay; they are not a catch-up-time estimate. [4]

A caught-up idle standby can retain its last measured delay briefly, then report NULL. Missing logical-replication tracking can also produce NULL. Converting every missing value to zero discards important uncertainty. [4]

An LSN difference measures bytes in PostgreSQL's WAL address space, not transactions or seconds. The hexadecimal representation does not change that unit. Compare compatible log histories and label the two endpoints. [5] [9]

Similar-looking observations answer different questions. Sources [4], [5] and [7].
ObservationMeaningAvoid inferring
Current WAL write position minus replay positionByte distance between those stagesNumber of lost transactions or seconds to recover
replay_lagRecent replay and notification delayA forecast of catch-up time
Time since last replayed transactionAge of the latest replayed commit/abort timestampProof of backlog during an idle period

Function names also need care: pg_current_wal_lsn() identifies the write position, whereas the insert and flush functions identify other stages. pg_last_wal_receive_lsn() already describes data received and synced to disk. The last replayed transaction timestamp can remain unchanged while the system is idle, so its age alone is not evidence of queued work. [7]

Record evidence before declaring a failover safe

Hesela's diagnostic checklist is an editorial synthesis, not an automated failover procedure:

  1. Record the commit policy and required replica membership for the affected transactions.
  2. Capture the candidate's write, flush and replay positions with timestamps and log-history context.
  3. Separate acknowledged transactions from requests whose outcome the client never learned.
  4. Check promotion eligibility and fencing independently of replica freshness.

A client can miss the success response for a transaction that the primary later recovers as committed. A missing acknowledgement is not proof of rollback. Treat that as an uncertain completion problem, not permission to retry blindly. [3]

Method and limits

This is a documentation and paper review, not a replication experiment. We compared PostgreSQL 18, the DRBD 9 guide, Swordfish 1.2.8 and the original OSDI 2004 chain-replication paper. No failover was executed, and no latency, loss probability or recovery time was measured. These reference versions are not a claim about the newest available release. Verify actual settings, storage flush behavior and failure domains before applying the conclusions.

Machine-readable definitions: synchronous replication, asynchronous replication, replication lag, log sequence number and storage mirroring.

Primary sources

  1. PostgreSQL 18: WAL settings, synchronous_commit
  2. PostgreSQL 18: synchronous_standby_names
  3. PostgreSQL 18: warm standby and synchronous replication
  4. PostgreSQL 18: pg_stat_replication and lag semantics
  5. PostgreSQL 18: pg_lsn type
  6. LINBIT DRBD 9 guide: section 2.3, replication modes
  7. PostgreSQL 18: WAL and recovery information functions
  8. SNIA Swordfish 1.2.8: ReplicaType Mirror
  9. PostgreSQL 18: timeline history and recovery branches
  10. PostgreSQL 18: Repeatable Read snapshot semantics
  11. Robbert van Renesse and Fred B. Schneider: Chain Replication for Supporting High Throughput and Availability, OSDI 2004, pp. 91-104

Accessed 12 October 2026. Conclusions are scoped to the cited documentation.