Skip to content

Redis persistence (RDB and AOF) and eviction policies

Persistence decides what a restart brings back; the eviction policy decides what a full Redis deletes, and each instance has exactly one.

Predict first

Before you read: predict

ExamHall's question cache and its BullMQ grading queue share one Redis with a maxmemory cap. After grading jobs went missing, the team switched its policy from allkeys-lru to volatile-lru, since BullMQ's keys carry no TTL. The question cache writes its entries with plain SET, also with no TTL. At the 09:00 exam start, 200 grading jobs are waiting and the cache writes about 30 times what the free memory holds.

What happens?

Pick one

The 30-second version

Redis keeps everything in RAM. A crash loses every write since the last RDB snapshot; an AOF loses at most about a second. At maxmemory the policy decides: noeviction refuses what may add data, allkeys-* evicts any key, volatile-* evicts only keys with a TTL and otherwise refuses. One instance has one policy, so keep queues apart from caches.

Persistence decides what a restart brings back; the eviction policy decides what a full Redis deletes, and each instance has exactly one.

How it works

Step 1 of 13

RAM first. Redis serves every key from memory. Persistence writes copies to disk, and a restarted process loads them back.

Analogy: A police station's evidence store

Every exhibit sits on the store's shelves, and nothing is kept anywhere else.

At the evidence store In Redis
the quarterly audit photographs every shelf; after a fire the photographs show the store as it was then an RDB snapshot and what a crash loses (steps 2–3)
the officer closing up properly photographs the shelves first; a fire takes no photograph a clean stop saves, SIGKILL does not (step 4)
the custody book records each exhibit in and out as it happens, and replaying it rebuilds the store the AOF (step 5)
the shelves are full maxmemory (step 7)
the hatch refuses anything that might need more shelf space noeviction (step 8)
a clear-out destroys whatever has sat untouched longest allkeys-lru (step 9)
a clear-out may destroy only exhibits already given a disposal date; with none dated, the hatch can only refuse volatile-* (step 10)
counterfeit goods awaiting routine destruction share the shelves with evidence for open cases, under one clear-out rule one instance, one policy (step 11)

In real terms: for each Redis you run, write down what a restart must bring back and what may be deleted when it is full; if two kinds of data give different answers, they need two instances.

Breaks down when: destroying an exhibit takes a signed form; Redis evicts a key silently, and only a counter moves.

Contrasting case: a pure cache that can be refilled from Postgres needs neither persistence nor noeviction: losing any key costs one miss.

Examples, run for real

4.1 ExamHall: the queue that shared the cache's policy

EXH-5020: at ExamHall's 09:00 exam start the question cache and the BullMQ grading queue shared one Redis running allkeys-lru. The cache's writes filled memory, and Redis evicted the grading jobs' keys to make room. MR !5320 gives the queue its own Redis with noeviction and leaves the cache on allkeys-lru.

4.1 EXH-5020 one Redis, allkeys-lru: 200 grading jobs, then 60000 question-cache writes · cache writes refused 0 · grading jobs kept 0 of 200
4.1 MR !5320 queue Redis (noeviction) + cache Redis (allkeys-lru): the same writes · cache writes refused 0 · grading jobs kept 200 of 200
4.1 MR !5320 20000 more jobs into the full queue Redis · added until it was full · refused with an OOM error the rest · other errors 0 · the first 200 jobs kept 200 of 200

Every grading job was gone and no write was refused, so nothing reported an error. After the split, the jobs survive the same writes, and a producer that overfills the queue's Redis gets an OOM error instead (steps 11–12).

4.2 Payments ledger: no cap in a 64 MB container

A ledger's FX-rate cache runs in a container limited to 64 MB, first with no maxmemory, then with maxmemory 40mb and allkeys-lru.

4.2 payments ledger FX cache in a 64 MB container, no maxmemory (0, the default): 200000 writes · kernel OOM kills 1 · new redis-server process yes · keys afterwards none
4.2 payments ledger FX cache in a 64 MB container, maxmemory 40mb, allkeys-lru: 200000 writes · kernel OOM kills 0 · new redis-server process no · keys afterwards some

With no cap, the kernel killed Redis and the restarted process came back empty; with a cap below the container's limit, Redis evicted keys and kept running (steps 7, 13).

Picture it

a crowded quick-access desk beside a durable bound archive, while an attendant removes an old optional folder from the desk (the asset map's description).
An illustration to help it stick. The mechanism is in the sections above.

Try it

Answer first, then check. Nothing is saved.

Question 1 of 6

A payments API keeps two kinds of keys in one Redis with a maxmemory cap: FX-rate cache entries (plain SET, no TTL, fetched again on a miss) and 500 idempotency keys (SET … EX 86400), which must outlive any retry or a retried charge runs twice. The platform team runs every shared Redis on volatile-lru and will not add an instance. At month-end the FX job writes about 30 times what the free memory holds.

Which way of writing the two kinds keeps every idempotency key while every FX-rate write still succeeds?

Pick one

Question 2 of 6

A ledger caches posting confirmations on two Redis servers. X runs save 900 1 and appendonly no, and its last snapshot ran right after posting 300. Y runs appendonly yes, appendfsync everysec and save "". Both receive the same 500 postings, the last 200 within a minute. After the last one is acknowledged, the Redis process on each machine is killed with kill -9, a process kill, not a power cut: the machines stay up and Redis restarts at once.

How many postings does each server load?

Pick one

Question 3 of 6

A payments ledger's job queue has its own Redis with noeviction, and a backlog has filled it past maxmemory. The API then sends, in this order: GET a posting's status, APPEND a line to an existing audit string, EXPIRE an existing idempotency key in one hour, LPOP the next job ID from an existing list.

Which commands succeed?

Pick one

Question 4 of 6

A ledger's FX-rate cache runs Redis in a container limited to 64 MB (--memory 64m, no swap), with maxmemory 200mb, allkeys-lru and no persistence (save "", no AOF). At month-end the FX job writes 150,000 rates of 512 bytes each, about 75 MB of values.

What happens?

Pick one

Question 5 of 6

A chat service holds presence sessions in a Redis started from the redis:7-alpine image with no config file. After the 120th session an operator runs BGSAVE, which finishes; 80 more sessions follow. A few seconds after the last write, the Redis process is restarted: once after a clean stop (SIGTERM, which docker stop sends first), once after a crash (kill -9).

How many sessions does each restart bring back?

Pick one

Question 6 of 6

A video service keeps viewer sessions (SET … EX 86400) on a Redis of their own, with AOF on and a maxmemory cap. Viewers who have signed in read their session on every request. The goal: no viewer who has signed in is ever logged out by memory pressure; refusing a new sign-in while memory is full is acceptable.

Which maxmemory-policy meets the goal?

Pick one

Go deeper

Pro tips
  1. Kill it before you trust it. In staging, write a known number of keys, kill -9 the Redis process, let it restart, and count what came back. When: before putting sessions, idempotency keys or a queue on a Redis (steps 2–5). Verify: each sends SIGKILL to the Redis process and counts the keys the restarted process loaded.
  2. Set maxmemory below the container's memory limit. The Redis docs advise leaving "a little RAM free to store the buffers" when persistence or replication is on. When: any Redis in a container or VM with a hard memory limit (steps 7, 13).
Source
  • Redis docs, Redis persistence (source content/operate/oss_and_stack/management/persistence.md, redis/docs branch main): https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/ · fetched 2026-10-18. "RDB persistence performs point-in-time snapshots of your dataset at specified intervals"; "in case of Redis stopping working without a correct shutdown for any reason you should be prepared to lose the latest minutes of data"; "If your computer running Redis stops, your power line fails, or you accidentally kill -9 your instance, the latest data written to Redis will be lost"; "When you restart Redis it will re-play the AOF to rebuild the state"; "you may lose 1 second of data if there is a disaster"; "The suggested (and default) policy is to fsync every second" (steps 1–5). Valid as of 2026-10-18.
  • Redis docs, Key eviction (source content/develop/reference/eviction/index.md, redis/docs branch main): https://redis.io/docs/latest/develop/reference/eviction/ · fetched 2026-10-18. "Set maxmemory to zero to specify that you don't want to limit the memory for the dataset. This is the default behavior for 64-bit systems"; "Keys are not evicted but the server will return an error when you try to execute commands that cache new data"; "Note that commands that only read existing data still work as normal"; "The volatile-xxx policies behave like noeviction if no keys have an associated expiration"; "you should consider running two separate Redis instances in a case like this, if possible"; "we recommend that you set maxmemory to leave a little RAM free to store the buffers" (steps 7–11, tip 2). Valid as of 2026-10-18.
  • BullMQ docs, Going to production, Max memory policy (source docs/gitbook/guide/going-to-production.md, taskforcesh/bullmq branch master): https://docs.bullmq.io/guide/going-to-production · fetched 2026-10-18. "BullMQ on the other hand cannot work properly if Redis evicts keys arbitrarily"; "This is the only setting that guarantees the correct behavior of the queues" (step 12). Valid as of 2026-10-18.

Checked against the tools and docs as of 2026-10-18.