EP · Overview — course hub
Keeping the state that matters.
EchoMQ enqueues on Valkey — a job on disk within a 1s window, on one box. Echo Persistence is everything beyond that for the state that must not be lost or must live off the machine: Champ accepts at in-heap speed with a fsync per K records, a transactional page-store commits each batch as one LSN replicated to Tigris, and the same model is built twice — native Elixir on CubDB and Rust on Fjall.
Grounding: docs/graft (graft.design.md · graft.engine-split.design.md) · docs/echo_mq (emq.roadmap.md) · echo/apps/echo_store · echo/apps/echo_graft — every figure verbatim from a committed record. Numbers are single-core sandbox measurements against MinIO; the spread between tiers is the lesson, not the absolutes.
The one knob is durable-records-per-fsync. A factor of 469 separates strict per-commit (Oban, 718 jobs/s) from no durability (Memory, 336,961 jobs/s); Oban single → batch is a factor of 18 from spreading one fsync across 1,000 jobs. Champ’s K and Graft’s batch are how the strict-and-replicated tier stays off that floor.
The one knob
graft.design.mdEvery engine accepts a job and decides two things at once: how much of it survives a crash, and how fast it says yes. Those are the same knob — the fsync is fixed cost, and throughput is how many durable records you amortize it across. An in-memory map rides infinitely many records per fsync and loses everything on a crash; Oban’s single-insert rides one durable record per fsync and loses nothing.
So the design question for Echo Persistence is not whether to fsync, but how to reach a per-commit, replicated guarantee without collapsing to the per-commit floor. The answer pairs Champ — an in-memory structure with a checkpoint every K records — as the accept tier, and Graft — a transactional page-store replicated to Tigris — as the commit tier, with the commit LSN published over EchoMQ as the change-feed.
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
reading → throughput tracks durable records per fsync · factor of 469 strict→none
The three dives
overviewThe durability spectrum
The four-way shootout read mechanically, and the two independent axes — the loss window, and whether state leaves the box.
Dive 2The two-tier shape
Champ accepts at in-heap speed; Graft commits one LSN, replicated to Tigris behind a conditional-write fence. The seam, and the per-call durability mode.
Dive 3Persistence in the platform
The four storage tiers, Echo Bus beside Echo Persistence, the durability dial per queue, and the two engines that coexist.
References & sources
- Echo records
- graft.design.mdthe two-tier design and the shootout
- graft.engine-split.design.mdthe two coexisting engines
- emq.roadmap.mdEchoMQ, the bus the change-feed rides
- External
- Valkey persistence (AOF)the inherited 1s window
- orbitinghail/graftthe transactional model (read-only idea source, MIT/Apache-2.0)
- Tigris object conditionalscreate-if-not-exists, the commit fence
- Designing Data-Intensive Applications, Kleppmann 2017WAL, group commit, replication
- Design reference
- Redis Patterns Appliedthe course sheet this design follows, re-themed