← the depth behind redis-patterns R1 · Caching
The Cache · pillar III
Serve reads
from the near-cache
Answer from memory when you can, fall through to the store when you must — and never let a herd fill it twice.
The Cache is the third pillar, and it stands in front of the other two. Where the Queue distributes
work and the Bus broadcasts signals, the Cache serves reads. It is a declared
near-cache — an L1 ETS table in front of the L2 Valkey the bus already runs on — read
cache-aside: a hit is a caller-side :ets.lookup that never enters the
owning process, and the owner is consulted only on a miss, where the second law holds: one fill per
herd. Concurrent misses coalesce onto a single loader; expiry is jittered so no cohort
dies together; and a full cache degrades to pass-through, it never fails. Every value is framed
with its writer's mint-time version — the seed of the coherence that keeps the caches
honest. It is all real code, grounded in echo/apps/echo_store.
The read, cache-aside
A cache-aside read tries the layers in order and stops at the first that answers. The fast path never leaves
the caller: a hit is a lookup in a public ETS table, in your process, costing nothing but the lookup.
Only a miss consults the owner — and there a miss in front of a thundering herd becomes one
fill, not a thousand. Pick a path to read what happens, the Valkey command beneath it, and the source the
fetch/3 answer is tagged with.
Cache-aside · pick a path
One read, tried in order: L1 answers in your own process, L2 answers from the shared store, the loader answers once for the whole herd — and the clock, jittered, makes sure no cohort ever asks again all at once.
The modules
Three modules and the closing workshop are ready — each module a hub and three dives, the workshop one end-to-end build. Each
grounds in the real echo/apps/echo_store code — the declared tiers and the
cache-aside read, then single-flight and the jittered clock that keep it cheap under a herd and bounded under
pressure.
Cache-aside, two layers
The declared near-cache: L1 ETS over L2 Valkey on ecc:{q}:id, the cache-aside fetch/3, and the version-framed write.
Single-flight & jittered TTL
One loader for a thundering herd; cohorts that never expire in step; a full cache that degrades to pass-through, never to failure.
Coherence — newer wins on the Bus
A message about a name: two identities, the eleven-byte mint comparison, the broadcast and job lanes, server-assisted tracking.
Workshop
Hit at ETS speed, survive a herd with one fill, watch a jittered cohort expire, then invalidate from another node.
Redis Patterns Applied
This is the depth behind the Redis Patterns Applied chapters that door here: R1 · Caching — the cache-aside, stampede-prevention, and session patterns this pillar applies in real code, and R5 · Streams & Events — the bus-coherent invalidation that keeps a versioned fill current. There the pattern is the door; here is the near-cache it names.
The version on every row
A cache that serves a read must also learn when that read goes stale. Every value here is framed with its
writer's mint-time version — a 14-byte branded id stored as version
<> value — and coherence is the rule that compares two such versions and lets the
newer win, with no coordinator and no clock but the one inside every id. That is the third
module. The manuscript chapter these figures realize is
The Branded Component System · the Store; the durable floor a coherence job
survives a crash on is Echo Persistence.
The cache and the two executors
The cache sends ordinary Valkey commands: GET, SET … PX
and DEL on its ecc: keys, PUBLISH on the
broadcast lane, and CLIENT TRACKING for server-assisted invalidation. Two of its moves
are scripts: the conditional drop is an inline Lua script, and the job lane enqueues through EchoMQ’s fair
lanes, which run only as scripts. Every connection it opens is an EchoMQ connector on its default wire 4, which
reads {emq}:version on connect: it seeds the wire 4 brand when the key is absent and
stops on any other brand. Neither script names a native verb, so a wire: 6 connection
would refuse both, and the cache serves from a wire 4 node. Trafikist teaches
the native executor.
The rest of the system
The Cache is one reading of the shared substrate. The Queue distributes work over the same
wire; the Bus broadcasts signals and keeps a replayable log; the Proof chapter
shows the whole system holds. The Protocol below them all — the keyspace the
ecc: prefix stands beside — is ready to read now.
The Protocol
The substrate the Cache stands beside: the braced keyspace, the record, the Lua layer, the branded-id gate.
The Queue
Distribute work: the lifecycle, jobs, lanes, the consumer, batches, flows.
The Bus
Broadcast signals: fire-and-forget events and a retained, replayable log ordered by mint.
The Proof
The system holds: the conformance suite, telemetry and the read plane, the benchmark named as the frontier.
Every chapter is ready to read: the Protocol, the Queue, the Bus, the Cache and the Proof.
References
Sources
- Erlang/OTP — the ets module — the public, read-concurrent L1 table a hit reads directly, in the caller's process.
- Valkey — Cluster specification — the
{table}hashtag lands everyecc:key of one cache on one of 16384 slots. - Söderqvist — A new hash table — the L2 Valkey the near-cache fronts, costed at rest.
- Helland — Life Beyond Distributed Transactions — the entity addressed by a key, cached close to where it is used.
- King — Announcing Snowflake — the time-ordered id every cached value is framed with.
Related in this course
- The Bus — the wire a coherence message broadcasts over.
- The Queue — the fair lanes a crash-surviving coherence job rides.
- The Protocol — the keyspace and branded-id gate the
ecc:prefix stands beside. - The Branded Component System · the Store — the manuscript chapter this pillar realizes.
- Echo Persistence — the durable floor beneath the volatile tiers.