Skip to main content

Caching Design Patterns

Introduction

Caching reduces latency and offloads primary data stores by serving hot data from faster storage (usually memory). Good cache design balances freshness, consistency, and cost, while handling failure modes like thundering herds and stale reads.

Core Patterns

  • Cache-Aside (Lazy Load): Application reads cache first; on miss, read DB, then populate cache with TTL. On writes, update DB and invalidate cache. Simple and resilient; risk of brief stale reads and thundering herd on popular key expiry.
  • Write-Through: Application writes to cache; cache synchronously writes to DB before acknowledging. Strong consistency between cache and DB; higher write latency.
  • Write-Back (Write-Behind): Application writes to cache; cache acknowledges quickly and flushes asynchronously to DB. Great write latency and batching; risk of data loss if cache fails before flush; needs recovery.
  • Read-Through: Cache is the read facade; it loads from DB automatically on miss. Similar freshness trade-offs as cache-aside but with loading logic in cache layer.
  • TTL vs Invalidation: TTL provides passive freshness and memory control; explicit invalidation (after writes) keeps hot keys correct. Many systems combine both.

Consistency & Freshness

  • Pick TTL based on staleness tolerance: short TTL for fast-changing data; long TTL for read-heavy stable data.
  • Use active invalidation on writes for correctness-critical data; pair with TTL as a safety net.
  • Watch for race conditions between DB writes and cache invalidations; consider per-key locks or versioned values if needed.

Operational Concerns

  • Thundering Herd: Protect with request coalescing, per-key mutex/locking, stale-while-revalidate, or tiered caches.
  • Hot Keys: Shard/replicate, use local caches (per-instance), or introduce jittered TTL to spread expiries.
  • Capacity & Eviction: Choose eviction policies (LRU/LFU), size keys carefully, and monitor hit/miss ratios.
  • Failure Modes: If cache is down, ensure the system degrades (slower DB reads) rather than fails; rate-limit to protect the DB.
  • Security: Guard access with auth, TLS, and network isolation; avoid sensitive data in shared caches without encryption.

Beyond Basic Caching (Common Redis Uses)

  • Session Store: Centralize user sessions to keep stateless app servers; align TTL with session expiry.
  • Rate Limiting: Atomic counters (INCR/TTL) for fixed window; or sliding/log-based algorithms for smoother limits.
  • Pub/Sub & Streams: Event fan-out, lightweight messaging, and async workflows.
  • Locks & Leases: Distributed locks with expirations; use carefully to avoid deadlocks and ensure timeouts.

Strategy Comparison (When to Use)

  • Cache-Aside: Default choice for read-heavy workloads; simple and resilient when cache is unavailable.
  • Write-Through: Use when post-write reads must see fresh data and write latency is acceptable.
  • Write-Back: Use when write latency must be minimal and occasional loss is tolerable, with a solid durability/replay plan.

Quick Checklist

  • Choose pattern: cache-aside vs write-through vs write-back.
  • Define TTLs and invalidation rules per key type.
  • Protect against thundering herd and hot keys.
  • Monitor hit/miss, latency, eviction, and error rates.
  • Plan failure behavior when cache is unavailable.
  • Secure the cache endpoint and data in transit.