jonnify·redis /redis-patterns/data-modeling/primary-database/noeviction

R7.01.2 · dive 2

Refuse the write, keep the record.

maxmemory-policy is a menu. The cache policies delete keys under pressure to keep serving; noeviction refuses the write instead — so nothing stored is ever lost.

If Valkey holds the record of truth, eviction is silent data loss: a job, a leaderboard row, a guess lock, gone with no trace. A system of record runs noeviction, and memory pressure becomes a loud error to alert on, not a vanished record. Select a policy; the readout reports what it sacrifices at the cap — a stored key, or the incoming write.

One question, three answers: what gives at the maxmemory cap? Select a policy; the readout reports what it drops to satisfy a write.
at a full keyspace, a write arrives — what gives? noeviction refuses the write · returns an OOM error · keeps every key KEEPS DATA allkeys-lru evicts the coldest key (whole keyspace) · then accepts the write DROPS A KEY volatile-ttl evicts the shortest-TTL key · only keys with a TTL are eligible DROPS A KEY
§2

The same write, two postures

noeviction.md · under pressure

Put the same write — a new job row at a full keyspace — to two servers, one on allkeys-lru and one on noeviction, and the divergence is the whole lesson. Under allkeys-lru the write succeeds, but to make room the server deletes the key it judges coldest. If that key was the only copy of a record, it is gone — silently, with nothing in the response to say so. Under noeviction the write fails with an OOM error, nothing stored is lost, and the alert fires on used_memory crossing the threshold.

A write at a full keyspace: loud failure, or silent loss. Select the policy on the server; read what happens to the write and to the stored record.
the keyspace, at the cap maxmemory job job job coldLRU + a new write arrives → OOM error — write refused (loud) every stored key survives memory pressure → an alert, not a leak write accepted — the cold key evicted (silent) if that key was the only copy — record lost no warning in the response select a policy to see the outcome —>

The trade is one-directional: noeviction gives up accepting writes under pressure and buys the guarantee that no stored record is ever dropped. For a cache that is the wrong trade; for a record of truth it is the only acceptable one.

§3

In EchoMQ — the job HASH is the record of truth

infra/valkey/conf/valkey.conf · the tuning surface

EchoMQ's job row has no second canonical copy. The enqueue script writes the row in one atomic step — HSET emq:{q}:job:<JOB-id> state pending attempts 0 payload <body> — and claim / complete / retry mutate that same HASH. There is no shadow row in Postgres to fall back on if the key disappears. That is why EchoMQ's Valkey runs noeviction: an evicted job key is a lost job, and a queue that silently drops keys is a queue that silently loses work.

infra/valkey/conf/valkey.conf · the committed eviction posturefrozen
# Memory: a loud guardrail, not a working ceiling.
# noeviction means a runaway keyspace REJECTS writes loudly instead of being OOM-killed silently.
maxmemory 512mb
maxmemory-policy noeviction
maxmemory-clients 64mb

# Fail the write rather than acknowledge data that may not survive.
propagation-error-behavior panic

Two design choices ride alongside it. First, maxmemory is a guardrail set far above the working set, not a working ceiling — the live dataset is single-digit megabytes, so 512 MB leaves roughly half the box for fork copy-on-write and buffers, and the cap exists to turn a runaway into an alert long before the OOM killer acts. Second, propagation-error-behavior panic makes the server fail a write rather than acknowledge data that may not survive — the same posture as noeviction, applied to propagation rather than to memory: refuse, do not pretend.

bcs.8.md · B8.2 · the principle for a job storefrozen
Eviction is the wrong posture for a job store: a queue that
silently drops keys is a queue that silently loses work, so
memory pressure must surface as write errors and alerts.

Notes on Valkeymaxmemory-policy selects what happens at the maxmemory cap: the allkeys-* policies evict from the whole keyspace, the volatile-* policies evict only keys with a TTL, and noeviction rejects writes with an OOM error while continuing to serve reads — valkey.io/topics/lru-cache.

the pattern

The eviction-policy menu: cache policies delete a key under pressure to keep serving; noeviction refuses the write instead, so nothing stored is lost.

its EchoMQ application

EchoMQ chooses noeviction because the emq:{q}:job HASH is the record of truth — an evicted key is a lost job. maxmemory is a guardrail far above the working set, paired with propagation-error-behavior panic.

The eviction policy is the line between a cache and a system of record. EchoMQ runs noeviction because the job HASH has no second home: memory pressure must surface as a write error and an alert, never as a vanished job.

/bcs/fly/valkey-on-a-fly-machine

The production posture of this config

This is the committed tuning surface; its production reasoning — why maxmemory sits far above the working set, how the fork copy-on-write spike is budgeted, and why eviction is the wrong posture for a job store — is the subject of Valkey on a Fly machine in the Branded Component System course. The persistence side of the same record-of-truth posture is the next dive.

§4

References

sources · related

Sources

  • Valkey — Key eviction — the maxmemory-policy menu: the LRU/LFU approximations, the volatile vs allkeys split, and noeviction.
  • Valkey — CONFIG SET — set maxmemory and maxmemory-policy at runtime, without a restart.
  • Valkey — Persistence — AOF and RDB, the durability beneath the record of truth this policy protects.
  • Valkey — HSET — the command that writes the job HASH the eviction policy must never drop.

Related in this course