RizTech Academy logo
RizTech Academy
Key-Value Stores and CachingLesson 6 of 625 min

Persistence, and what a cache must never be

This module has treated Redis as a fast, disposable copy. But Redis can persist to disk, and that capability leads to the single most expensive mistake people make with it: mistaking "can persist" for "is a database". This lesson is what Redis persistence actually guarantees, and the firm line about what a cache must never be trusted to do.

Redis can persist — two mechanisms

Redis is memory-first, but it writes to disk in one of two ways so it can survive a restart.

RDB — point-in-time snapshots. Every so often, Redis forks and dumps the entire dataset to a compact file. The default (on the standard image) is:

CONFIG GET save   →   save 3600 1   300 100   60 10000

Read as three rules: snapshot if ≥1 key changed in the last 3600s, or ≥100 in 300s, or ≥10000 in 60s. Snapshots are compact and restart-fast, but everything written since the last snapshot is lost on a crash. With those defaults, a crash can lose up to an hour of writes.

AOF — append-only file. Redis logs every write command to a file, replayed on restart. It is off by default (appendonly no) and its durability depends on how often it flushes to disk:

CONFIG GET appendfsync   →   everysec
  • always — fsync every write. Safest, slowest, closest to a real database's durability.
  • everysec — fsync once a second. The default when AOF is on: lose at most one second of writes on a crash. The usual choice.
  • no — let the OS decide. Fastest, least safe.

You can run both — AOF for durability, RDB for fast restarts and backups — which is the recommended production posture when Redis holds anything you care about.

But persistence is not durability in the database sense

Here is the crux, and read it twice, because it is where the disaster lives. Even with AOF at everysec, and even with both mechanisms on:

  • everysec can lose up to a second of writes. A relational COMMIT cannot lose an acknowledged transaction; Redis, at its common durability setting, can. That gap is the whole difference.
  • A snapshot loses everything since it was taken — up to an hour with the defaults.
  • Replication is asynchronous, so a failover to a replica can lose the writes that had not yet reached it — the same w:1-style window you saw in MongoDB.
  • There are no transactions across keys with rollback, no foreign keys, no constraints. Nothing protects the integrity of the data, only (partially) its survival.

So Redis persistence answers "will my data probably survive a restart?" — usually yes. It does not answer "is every acknowledged write guaranteed on disk, consistent, and recoverable?" — which is what a database means by durability, and what the D in ACID promises. Redis gives you better than nothing, not as good as PostgreSQL.

The line: what a cache must never be

From this follows the rule the whole module has been building toward:

Never store data in Redis that you cannot afford to lose and cannot reconstruct from somewhere else.

The safe test is the one from the first lesson: if Redis vanished entirely right now, your application should become slower, not wrong. Cached query results — fine, they rebuild from PostgreSQL. Sessions — usually acceptable (users log in again), and a real trade-off you choose deliberately. But:

  • The only copy of a user's order? No. If Redis is the sole record, a crash between snapshots loses real orders — money and trust gone.
  • A financial balance or ledger? Absolutely not. This needs ACID; it belongs in PostgreSQL.
  • Anything with legal or audit weight? No.

The failure mode is always the same story: a team starts using Redis as a cache, notices it can persist, gradually starts keeping things only in Redis because it is fast and convenient, and one day a crash between snapshots — or an OOM kill, or a failover — loses data that existed nowhere else. The convenience is real and the loss is silent until it is catastrophic. That is the sentence to remember.

When Redis-as-primary is legitimate

Not never — but deliberately, and with eyes open:

  • Genuinely ephemeral data whose loss is acceptable by nature: rate-limit counters (a lost count resets a window, no harm), transient real-time state, a live leaderboard you can recompute.
  • With AOF always and replication, for data where Redis's speed is essential and you have accepted and engineered for the residual risk — a deliberate architecture, not a drift.
  • As the fast tier of a two-tier design, where PostgreSQL remains the durable source of truth and Redis holds a fast working copy that can always be rebuilt from it.

The distinction is deliberate versus accidental. "We chose Redis-as-primary for this ephemeral, recomputable data and configured it accordingly" is engineering. "We kept putting things in Redis until the important stuff lived there too" is the incident.

Redis's other limits, briefly

Durability is the big one; these matter too:

  • Everything must fit in RAM (plus overhead — persistence forks briefly need extra memory). You cannot cache a dataset larger than memory; that is what maxmemory and eviction are for.
  • Single-threaded for command execution. Blazing for fast operations, but one slow command blocks every client — the reason KEYS *, a big SORT, or a huge SMEMBERS are dangerous on a busy server.
  • No rich query language. No ad-hoc queries, no joins, no "find all users where…". You can only retrieve by key or by a structure you built in advance. Design your access patterns up front — even more than with MongoDB.
  • Scaling is different. Redis Cluster shards across nodes, but multi-key operations across shards are restricted, so you design keys with sharding in mind.

Each is a direct consequence of what makes Redis fast. They are the price of the speed, not defects.

The whole module in one frame

  • PostgreSQL — the durable, consistent, queryable source of truth. Start here. Most data belongs here.
  • Redis — a fast, in-memory, mostly-disposable layer for the hot path: caching, sessions, rate limits, leaderboards, queues.
  • The two together are the shape of almost every real web application, and using both on purpose is the polyglot-persistence idea the next module generalises.
  • The rule that keeps you safe: if Redis disappeared, the application should get slower, not wrong.

Check your work

Redis's two persistence mechanisms. RDB (point-in-time snapshots) and AOF (append-only command log).

What a crash loses with RDB. Everything written since the last snapshot — up to an hour with the defaults.

AOF's default state and its fsync options. Off by default; always (per write), everysec (the usual, ≤1s loss), no (OS-decided).

Why persistence is not database durability. everysec can lose a second; snapshots lose more; replication is async; and there are no cross-key transactions, foreign keys or constraints.

What Redis persistence does and does not answer. "Will it probably survive a restart?" yes; "is every acknowledged write guaranteed on disk and consistent?" no.

The rule for what a cache must never be. Never the only copy of data you cannot afford to lose and cannot reconstruct elsewhere.

The safe test. If Redis vanished, the app should get slower, not wrong.

Three things that must not live only in Redis. The sole copy of an order, a financial balance, anything with audit weight.

The classic failure pattern. Cache → notice persistence → gradually keep things only in Redis → lose data that existed nowhere else.

When Redis-as-primary is legitimate. Deliberately, for ephemeral or recomputable data, or with AOF always and replication and engineered-for risk — never by drift.

Three non-durability limits. RAM-bound size, single-threaded (one slow command blocks all), and no rich query language.

Practice

  1. Read CONFIG GET save and CONFIG GET appendonly on a fresh instance. State the default durability guarantee.
  2. Write data, force a snapshot with BGSAVE, then write more, then kill the container hard. On restart, confirm the post-snapshot writes are gone.
  3. Enable AOF (CONFIG SET appendonly yes), repeat the crash, and compare what survived.
  4. Reason about the worst-case data loss for everysec versus always versus RDB-only.
  5. For five kinds of data in an application you know, decide for each whether losing it in a crash is acceptable — and therefore whether it may live only in Redis.
  6. Find a case where a team might drift into Redis-as-primary. Describe the crash that exposes it.
  7. Run a deliberately slow command on a busy toy instance and observe other clients stall (single-threaded blocking).
  8. Design the key structure for a feature so that every access is by key — no ad-hoc query needed.
  9. Sketch a two-tier design for one feature: what is durable in PostgreSQL, what is fast in Redis, and how Redis rebuilds if lost.
  10. Write the one-sentence test you would apply before putting any new data in Redis.

Official documentation

Next module: the other database families — wide-column, graph, search, time-series and vector.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship