Redis and Key-Value Stores
A very fast cache with strong opinions about what it stores
Redis serves in-memory keys with fast atomic data structures, TTLs, and pub/sub. It is a cache, a queue, and a session store — not a durable warehouse.
What you will learn
- Choose between in-memory serving and durable stores
- Set TTL and eviction policies deliberately
- Use atomic ops and clusters without extending your failure surface
What is this?
Redis keeps a dictionary of keys in RAM, supporting strings, hashes, lists, sets, and sorted sets with atomic commands, TTLs, persistence snapshots, and pub/sub. Its speed comes from staying in memory; its durability and capacity come from a persistence config you actually configure.
Why do you need it?
- Every hot path (sessions, rate limits, counters, leaderboards) is a Redis use case.
- Misconfiguring TTLs and eviction is how a 'fast cache' silently becomes stale data at churn.
- It is one of the simplest ways to understand memory-centric workload design.
Mental model
A notepad next to the office coffee machine
A cache (Redis)
Fast to check, but nobody audits the notepad — if the page is stolen, nobody cares except that morning. Real truth lives in the database; the notepad is an accelerator and can be evicted.
How it works
- Single-threaded event loop executes commands serially, which makes each command atomic in one instance.
- Strings/binary/JSON, hashes for fields, lists for queues, sorted sets for rank and range queries.
- TTL expires a key; eviction policies (allkeys-lru, volatile-lru, noeviction) decide what dies when memory is full.
- Persistence: RDB snapshots are periodic; AOF is append-only log replayed at restart (with fsync policies).
- Clusters shard keys by hash slot and give up multi-key transactions across slots.
Where Redis sits in a request path.
Key commands
SETEX key 300 valueSet a key that lives for 300 seconds.
INCR hits / EXPIRE hits 60Atomic counter plus a rate-limit window.
CONFIG SET maxmemory-policy allkeys-lruLet the cache shed least-recently-used keys under pressure.
Examples
Cache-aside pattern with TTL
# read pathvalue = redis.get("user:123:profile")if value is None: value = db.query("SELECT * FROM users WHERE id=123").json # DB read redis.setex("user:123:profile", 300, value) # 5 min TTL # invalidation on writedb.update_user(123)redis.delete("user:123:profile")TTL bounds staleness; explicit delete on write keeps the cache warm and correct.
In production
- A session store with a 24h TTL carries login state for a fleet of web nodes.
- A rate limiter uses INCR + EXPIRE on a per-user key, capped by a second sorted-set bucket.
- A leaderboard for a game writes ZADD and reads ZREVRANGE for top-10 in O(log n).
Best practices
- Consider memory as a first-class cost: sum of key sizes × replicas should fit without thrashing.
- Set TTLs on cache-like keys; use an explicit eviction policy that matches your freshness contract.
- When a DB value changes, invalidate or version the key — rely on TTL as a backstop, not as the only invalidation.
- Batch pipeline round-trips (MGET/SETEX in one call) when the LAN round trip is not free.
Common mistakes
- Keeping no TTL on cache entries, so stale data outlives the source and the 'cache' becomes the source of truth by accident.
- Using noeviction on a small instance, then OOMing the host instead of evicting.
- Putting big whole-document payloads behind single keys, blowing memory and cache hit rates.
Debugging tips
- Redis INFO memory and keyspace_hits/miss ratio separate 'working set too large' from 'eviction too aggressive'.
- When keys vanish, check info evicted_keys and the maxmemory policy before blaming a bug.
- If writes vanish from the cache but the DB has them, confirm persistence is configured rather than graceful shutdown.
Interview checkpoint
Quick quiz
A Redis RDB snapshot is a full copy that, if the process crashes mid-write, may lose recent data.
What happens when maxmemory is reached with policy allkeys-lru?