jonnify·persistence /echo-persistence/overview/the-durability-spectrum

EP · Overview · Dive 1

The durability spectrum.

Durability is not a checkbox; it is a position on a spectrum, set deliberately per queue. Read from one measurement, the spectrum has a single mechanism behind it — and one more axis that the throughput number hides: whether the durable state ever leaves the box.

§1

The measurement

graft.design.md

Four engines recorded the same 20,000 jobs on one shared vCPU, with Postgres durable (synchronous_commit=on) and Redis durable (AOF everysec). The result spans three orders of magnitude, and the spread has exactly one explanation: throughput tracks how many durable records ride each fsync. The fsync is fixed cost; everything else is how many jobs you amortize it across.

shootout · N=20,000 · 1 vCPUMEASURED
engine            store                       durability            single        batch
Memory            in-memory map               none                  336,961       —
Champ K=10000     local fsync snapshot        bounded ≤ 10,000 rec   103,970       —
Champ K=1000      local fsync snapshot        bounded ≤ 1,000 rec     33,989       —
BullMQ            Redis AOF everysec          bounded 1s              6,388    16,180
Oban              Postgres sync commit        strict per-commit         718    13,235
Memory rides ∞ records/fsync · Champ rides K · Oban-batch rides a txn · Oban-single rides one

A factor of 469 separates strict per-commit durability (Oban, 718 jobs/s) from no durability (Memory, 336,961 jobs/s). Within Oban, the single-insert path commits once per job; insert_all writes 1,000 jobs per transaction and reaches 13,235 — a factor of 18, purely from spreading one fsync across the batch. Champ reaches the same class continuously, because its checkpoint amortizes the fsync over K records without the caller ever holding a batch.

The lesson is mechanical, not magical: to make a strong durability guarantee affordable, raise the durable-records-per-fsync — with K (Champ), a transaction (Oban-batch), or a group-commit. That single lever is what the whole two-tier design pulls.

§2

Two axes, one decision

graft.design.md

The shootout measures one axis: the loss window, from “none” to “strict per-commit.” A second axis is independent of it — does the durable state leave the machine? Oban is strict but single-node unless Postgres streaming replication is bolted on; Champ’s snapshot is bounded-loss and ships asynchronously. A tier can be strict-but-single-node, or bounded-but-replicated; the two choices do not move together.

Placing a queue therefore means choosing both — a loss window and a replication posture. A telemetry queue wants neither (in-memory, 336,961 jobs/s, holding nothing). A money queue wants both: per-commit and off-box. The rest of Echo Persistence is about reaching that far corner — per-commit and replicated — without paying the per-commit floor, which Dive 2 builds.

Place a queue. Select a workload to read where it should sit on both axes.
readout · Select a workload. The loss window and the replication posture are chosen separately.
§3

References & sources