Skip to content
About
Main content

Durability across a pipeline

When data passes through several systems, whose "yes" is the reader's promise, and for how long does it hold?

Every article so far asked what one system promises when it says "yes". A data platform is a chain: the ledger, an event stream, its consumers, an archive in object storage. The reader's question, "is this transfer safe?", is asked at the end of the chain, and every hop answers part of it.

This is the rule from fsync and flush barriers, "an acknowledgment is only as true as the least honest layer beneath it", applied to layers that are whole systems. It is where the durability question is most often answered wrong, because each team can truthfully say its own system is durable.


Each hop makes its own promise

HopWhat its "yes" meansSet byRung
Ledger committhe is flushed, and copied to a synchronous replicasynchronous_commit and friends4–5
Producer → broker (Kafka)acks=0: nothing was waited for. acks=1: the partition leader appended the record. acks=all: every in-sync replica has itproducer acks, topic min.insync.replicas0, 2 or 5
Broker storagethe record is in the of each replica; by default no broker flushes per messageflush.messages, flush.ms (off by default)2 per machine
Consumer → sinkthe consumer's bookmark (its offset) says the record was deliveredwhen the offset is committed—
Sink: object storea PUT returns success only after the object is stored redundantly; it is atomic, so there is no torn objectthe storage class5 or more

Two lines need a second look.

acks=all is rung 5 without rung 4. The record is in the memory of several brokers, none of which has flushed it. It survives the loss of one broker; it does not survive a power cut that takes all of them at once. That is a sound trade only when the replicas sit in independent failure domains, such as different racks or zones.

"All" means all in-sync replicas, and that set can shrink to one. When followers fall behind, they leave the in-sync set. With the default min.insync.replicas=1, acks=all then means "the leader has it": rung 2 on one machine, reported as success. min.insync.replicas=2 turns that case into an error the producer can see. And unclean.leader.election.enable (off by default) must stay off: turned on, it lets a replica that missed acknowledged records become the leader, and those records are gone.


Custody: who may forget, and when

Between two systems there are two "yes"es and a gap. The payments service commits the transfer, then publishes the event. A crash in the gap leaves the transfer durable in the ledger and absent from everything downstream, forever. No setting on either side closes it, because each side kept its own promise. The fix is to remove the second write: put the event in the ledger's own commit (transactional outbox), or read it from the ledger's log (log-based CDC). Either way the event becomes exactly as durable as the transfer. Why one fact must never be written to two systems is in Replay and dual-write avoidance.

Downstream, the same rule has a simpler form: a hop may forget its copy, or move its bookmark, only after the next hop's copy is durable. For a consumer the bookmark is its offset, and the order of the two writes is the delivery semantic: offset first loses a record on a crash, offset last repeats it, and storing the offset in the sink removes the choice (Consumer offsets and commit ordering). Durability's share is only the rule: the bookmark moves last.


Retention is a durability horizon

A log that deletes by time keeps its promise for its retention period and not a second longer. Kafka's default is 7 days (retention.ms). A consumer that is away longer finds its oldest records deleted; this is the "drop the laggard" policy from Log truncation and retention policies, and the loss is silent by design.

So a stream has two durability numbers, not one: what it survives (the rungs above) and for how long (its retention). Size retention to the longest outage of any consumer you will tolerate, and measure consumer lag in time against that retention, not in records.