Learning Redis - Caching Strategies & Design Patterns
Episode 11 of 21

Learning Redis - Caching Strategies & Design Patterns

This episode covers how Redis is used in the real world as a cache and infrastructure: Cache-Aside, Write-Through, and Write-Behind strategies, eviction policies, a rate limiter with Sorted Sets, Redlock-style distributed locks, and the session store pattern.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

The first three phases of this series equipped you with Redis commands and data structures. Episode 11 starts assembling them into real architectural patterns: how Redis is used as a cache, a request rate limiter, a distributed lock, and a session store.

This is the episode most asked about in backend interviews: when to use Cache-Aside, how to choose an eviction policy, and how a proper rate limiter works. You'll see how the data structures you've learned — Strings, Sorted Sets, Hashes — come together into solid patterns.

Caching Strategies

Cache-Aside (Lazy Loading)

The most common and easiest-to-understand strategy. The application reads the cache first; on a miss, it reads the database, then writes the result to the cache:

Cache-Aside flow
GET data:1 → cache hit? → return
            → cache miss → query DB → SET data:1 value EX 300

A short implementation in the application: check GET data:1, if nil it's a miss, fetch from the database, then SET data:1 value EX 300. The Cache-Aside advantage: simple, and the cache only holds data that's actually read. The weakness: the cache can go stale until the TTL expires — known as stale data.

Write-Through and Write-Behind

  • Write-Through: every database write is immediately also written to the cache synchronously. The advantage is the cache is always consistent; the drawback is extra latency on the write path, and rarely-read data still fills the cache.
  • Write-Behind (Write-Back): the application writes to the cache first, then the cache flushes to the database asynchronously. Very fast for write-heavy workloads, but there's a risk of data loss if the cache crashes before the flush completes.

Read-Through

The cache itself fetches data from the database on a miss (usually via a dedicated library). Application consumers only talk to the cache, not the database — but operating this layer is more complex.

StrategyReadWriteConsistencyComplexity
Cache-AsideDB on missManual cache updateCan be temporarily staleLow
Write-ThroughDB on missSync to cacheHighMedium
Write-BehindDB on missAsync to DBRisk of data lossHigh
Read-ThroughCache pulls from DBManualCan be staleMedium

For most applications, Cache-Aside + TTL is the most sensible starting choice.

Cache Eviction Policies

Understanding maxmemory

When maxmemory is reached, Redis must decide which keys to evict. This policy is set via maxmemory-policy:

Check the active eviction policy
redis-cli CONFIG GET maxmemory-policy

redis-cli CONFIG GET maxmemory-policy shows the current policy. The options you need to know:

  • allkeys-lru: evict whichever key has been used least recently (approximate LRU) — the common choice for a pure cache.
  • allkeys-lfu: evict the least frequently accessed keys — better for skewed access patterns.
  • volatile-lru: evict the least-used keys that have a TTL; keys without a TTL are left alone.
  • volatile-ttl: evict TTL keys that are closest to expiry.
  • noeviction: evict nothing; write commands error with OOM command not allowed when used memory > 'maxmemory'.

Info

If all your cache keys have a TTL, volatile-lru and allkeys-lru are equally effective. If permanent keys must be guaranteed to never disappear (e.g. reference data), use volatile-lru with TTLs only on cache keys.

For a pure cache with a hot access pattern, allkeys-lfu is often superior: frequently-read data survives, cold data gets evicted.

Common Caching Patterns

Rate Limiter with a Sorted Set (Sliding Window)

Limit requests per user with an accurate sliding window — the Sorted Set stores timestamps as scores, old elements are removed, then you count the number within the window:

Sliding window rate limiter
redis-cli ZREMRANGEBYSCORE rl:user:42 -inf 1700000000
redis-cli ZADD rl:user:42 1700000000 "req-1"
redis-cli ZCARD rl:user:42

This pattern removes requests older than the window (ZREMRANGEBYSCORE), adds the new request (ZADD), then checks ZCARD to see whether the limit has been exceeded. For full accuracy without race conditions, wrap this logic in a Lua script (episode 10) — that's why production rate limiters always use Lua.

Distributed Lock with Redlock

When several application instances must ensure only one is working (e.g. a single cron scheduler), use a distributed lock. Based on SET NX PX:

Acquire and release a distributed lock
redis-cli SET lock:job "instance-1" NX PX 30000
redis-cli EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end" 1 lock:job "instance-1"

The first line acquires the lock with SET ... NX PX 30000 — it only succeeds if the key doesn't exist yet, and it's valid for 30 seconds. The second line releases the lock only if the owner is correct (via Lua) — preventing deletion of another instance's lock. Redlock extends this pattern to several Redis nodes for higher tolerance, at the cost of added complexity.

Session Store with Hash + TTL

A pattern you already saw in episode 4, summarized here because it's a core web application pattern:

Production session store
redis-cli HSET session:9f3a userId 123 role "admin"
redis-cli EXPIRE session:9f3a 1800

HSET session:9f3a userId 123 role "admin" stores the session as an object, EXPIRE gives it a 30-minute lifetime. Expired sessions are cleaned up automatically by Redis — the application needs no cron cleanup. This pattern is used by almost every web framework with a Redis session store enabled.

Summary

Episode 11 assembled Redis data structures into production patterns: Cache-Aside, Write-Through, Write-Behind, and Read-Through strategies; eviction policies like allkeys-lru and allkeys-lfu; a Sorted Set-based rate limiter; Redlock distributed locking; and a Hash + TTL session store.

Key takeaways:

  • Cache-Aside is the default strategy: check cache, miss → read DB → write cache with TTL.
  • Write-Behind is fast but risks data loss on crash.
  • allkeys-lfu excels for hot access patterns; noeviction makes writes error when full.
  • A sliding window rate limiter is built from Sorted Set + Lua for atomic accuracy.
  • Distributed locks use SET key value NX PX; release must validate the owner via Lua.
  • Session store = Hash + TTL; expired sessions are cleaned automatically by Redis.

In the next episode, episode 12, we start the high availability phase: Replication (Master-Replica) & Redis Sentinel. You'll learn asynchronous replication with REPLICAOF, read scaling, then Redis Sentinel as a watchdog with automatic failover. Let's continue!

Learning Redis - Caching Strategies & Design Patterns | Learning Redis