Skip to content

Cache Invalidation

1. Decision

Implement active, event-driven Cache Invalidation (evicting keys immediately upon database mutations) as the primary strategy for data consistency, paired with short TTL safety nets to eliminate stale cache state.


2. 30-Second Answer

Phil Karlton famously declared Cache Invalidation one of the two hardest problems in Computer Science. Cache Invalidation is the process of declaring cached data invalid and purging or updating it when the underlying system of record changes. The two fundamental approaches are Programmatic Eviction (Application deletes key upon DB write) and Event-Driven CDC Invalidation (Change Data Capture reading DB WAL to publish invalidation events via Kafka/Redis Pub/Sub). For high-scale microservices, programmatic invalidation should evict keys (delete) rather than update keys to avoid out-of-order write race conditions. Pairing active invalidation with TTL safety nets ensures zero permanent stale data.


3. Decision Matrix

Option Best For Avoid When Latency Scalability Consistency Operational Complexity
Programmatic Eviction (Delete Key on Write) General application microservices, Cache-Aside pattern Read-heavy data where next read SLA requires pre-warmed cache Low Write penalty; Immediate eviction High Strong (Minimal staleness window) Low
Event-Driven CDC (Debezium + Kafka) Decoupled microservices, multi-cache invalidation fleets, polyglot persistence Simple monolithic applications with minimal traffic Asynchronous (10-50ms CDC pipeline lag) Extremely High (Decoupled background stream) High (Eventual consistency within ms) High (Requires Kafka + Debezium infra)
Active Key Update (Write-Through) Data that is read continuously and cannot tolerate cache miss latency Write-heavy applications, concurrent multi-threaded writes High Write penalty (Sync DB + Cache update) Medium Risk of stale data race conditions if un-locked Medium
Passive TTL Expiration Only Low-priority non-critical data, news feeds, search suggestions Strict consistency requirements, user account state Zero Write penalty High Weak (Stale window equals TTL duration) Very Low

4. Selection Rules

Requirement Best Choice Rationale / Example
Standard Application Cache-Aside Programmatic Key Eviction Delete cache key (DEL key) immediately after DB transaction commits
Decoupled Architecture (No App DB Access) CDC (Debezium + Kafka) Invalidate cache based on DB Write-Ahead Log events asynchronously
Prevent Race Conditions on Write Evict (Delete) Key Never update key directly on write; force next read to fetch fresh DB state
Invalidate Group of Related Keys Tag-Based / Prefix Eviction Invalidate by Redis Hash Tags or Redis SCAN + UNLINK by prefix patterns
Multi-Region Global CDN Invalidation CDN Purge API / Surrogate Keys Issue API cache purge using Fastly/Cloudflare Cache Tags (Surrogate-Key)
Zero Invalidation Failure Risk Active Eviction + Short TTL Event-driven deletion handles immediate consistency; TTL cleans missed events

5. Tradeoffs

  1. Key Eviction (Delete) vs Key Value Update
  2. Gain (Evict): Prevents out-of-order race conditions from overwriting fresh cache with stale values.
  3. Lose (Evict): Next read request incurs a cache miss and DB query latency.
  4. Programmatic Invalidation vs Event-Driven CDC Invalidation
  5. Gain (Programmatic): Invalidation happens immediately inside application transaction boundary.
  6. Lose (Programmatic): Couples application write paths to cache infrastructure; fails if app crashes post-DB commit.
  7. Event-Driven CDC Decoupling vs Asynchronous Pipeline Lag
  8. Gain (CDC): Zero application code coupling; guaranteed invalidation for every DB mutation regardless of origin.
  9. Lose (CDC): 10-50ms replication lag between DB WAL write and CDC cache invalidation execution.
  10. Fine-Grained Single Key Invalidation vs Bulk Prefix Purging
  11. Gain (Single Key): Surgical accuracy; leaves unrelated warm cache keys intact.
  12. Lose (Single Key): Requires managing complex mapping relationships between DB entities and cache key names.
  13. Real-Time Purge vs TTL Natural Expiration
  14. Gain (Real-Time): Instant consistency across user devices.
  15. Lose (Real-Time): Invalidation API call failures can leave stale keys until TTL expires.

6. Interview Counter Questions

  1. Why should you always DELETE a cache key on database write instead of UPDATING the key?
  2. How does a race condition occur between a DB Read Miss and a DB Write Invalidation?
  3. How do you handle cache invalidation failures when the DB commit succeeds but the Redis DEL command fails?
  4. How does Change Data Capture (CDC via Debezium) implement reliable cache invalidation?
  5. How do Cache Tags (Surrogate Keys) work in CDN cache invalidation?
  6. Why is running KEYS user:* for prefix cache invalidation dangerous in production Redis?
  7. What is the Dual-Write Problem in microservice caching architectures?
  8. How do you invalidate local in-memory caches (Caffeine) across 50 application nodes?
  9. What is Transactional Outbox Pattern and how does it solve cache invalidation consistency?
  10. How do you invalidate cached search/pagination results when a single record changes?

7. Gold Standard Answers

  1. Deleting the key is atomic and safe. Updating the key directly allows concurrent out-of-order writes (e.g., Write A commits after Write B but overwrites Cache) to permanently pollute the cache with stale data.
  2. Race: Read Miss fetches DB value V1 \(\rightarrow\) Write updates DB to V2 & evicts cache \(\rightarrow\) Read Miss writes stale V1 to cache. Prevent by setting short TTLs or using transactional outbox invalidation.
  3. Use Transactional Outbox Pattern or CDC. Alternatively, wrap invalidation in retries, or ensure keys have a short TTL safety net so stale data self-heals quickly.
  4. Debezium reads raw database Write-Ahead Logs (WAL/binlog) engine-level events, publishing change events to Kafka. A dedicated consumer worker reads Kafka and issues UNLINK commands to Redis, completely decoupled from app code.
  5. CDN responses include a Surrogate-Key: product-123 vendor-abc header. When product 123 updates, issue an API purge call for tag product-123, invalidating all cached URLs carrying that tag instantly across global edge nodes.
  6. KEYS is a blocking \(O(N)\) operation that freezes the single-threaded Redis event loop. Use SCAN with UNLINK (non-blocking async deletion) or organize keys in Redis Hashes (HSET/HDEL).
  7. Dual-Write problem occurs when an app writes to DB and Redis in separate network calls. If one fails or app crashes mid-way, DB and Cache become permanently out of sync.
  8. Broadcast invalidation messages over a Redis Pub/Sub topic or Kafka event bus. Every app instance listens to the topic and executes localCache.invalidate(key) locally upon receiving the event.
  9. Outbox Pattern: App writes domain change AND an invalidation event record into an outbox DB table inside a single ACID transaction. A background process (Debezium/Relay) reads the outbox table and executes Redis invalidations reliably.
  10. Either invalidate entire pagination version keys (e.g., user:123:posts:v2), use short TTLs on search results, or cache individual entity IDs and assemble paginated lists dynamically.

8. Common Mistakes

  • Updating cache keys directly on write instead of deleting (evicting) keys.
  • Executing blocking KEYS * commands in production Redis to invalidate groups of keys by wildcard prefix.
  • Triggering cache invalidation before the database transaction commits (causes immediate race conditions with concurrent reads).
  • Relying purely on application-level HTTP handlers for invalidation without fallback TTLs or CDC outbox pipelines.
  • Failing to synchronize local process memory caches across multiple load-balanced application instances.

9. Keywords

Cache Invalidation, Phil Karlton, Programmatic Eviction, CDC, Debezium, Surrogate Keys, Cache Tags, Dual-Write Problem, Transactional Outbox Pattern, UNLINK, SCAN, Redis Pub/Sub, Out-of-Order Writes.


10. Cheat Sheet

  • Golden Rule: Evict (Delete) cache keys on write. Never update key values directly to avoid write race conditions.
  • Timing Rule: Execute cache invalidation AFTER the database transaction successfully commits.
  • Dual-Write Fix: Use Transactional Outbox Pattern or CDC (Debezium + Kafka) to guarantee invalidation reliability.
  • Bulk Invalidation: Never use KEYS *. Use SCAN + UNLINK, Redis Hashes (HDEL), or CDN Surrogate Keys.
  • Safety Net: Always pair active invalidation with a fallback TTL to self-heal missed invalidation events.
  • Local Cache Sync: Broadcast invalidation events via Redis Pub/Sub to clear local Caffeine caches on all nodes.

11. Related Decisions