Full Stack • Java • System Design • Cloud • AI Engineering

Cache Invalidation in System Design

Learn Cache Invalidation from a System Design perspective. This guide explains why cache invalidation is one of the hardest problems in distributed systems, explores TTL, explicit invalidation, write-through, event-driven invalidation, versioning, Redis integration, Spring Boot architecture, and real-world examples from Amazon, Netflix, Uber, and Banking systems.


Introduction

One of the most famous quotes in Computer Science is:

"There are only two hard things in Computer Science: Cache Invalidation and Naming Things."

Imagine your application caches a product.

Product

↓

Price = $100

A few seconds later,

an administrator updates the price.

Price = $80

The database now contains:

$80

But Redis still contains:

$100

Customers continue seeing the wrong price.

This is called Stale Cache.

The process of removing or updating outdated cache entries is known as Cache Invalidation.


Learning Objectives

After completing this article, you will understand:

  • What is Cache Invalidation?
  • Why Cache Invalidation is Difficult
  • Cache Lifecycle
  • Stale Data
  • TTL
  • Explicit Invalidation
  • Event-Driven Invalidation
  • Version-Based Invalidation
  • Spring Boot Integration
  • Redis Integration
  • Best Practices

What is Cache Invalidation?

Cache Invalidation is the process of:

  • Removing outdated cache
  • Updating cache
  • Refreshing cached data

after the underlying data changes.


Why Cache Invalidation?

Without invalidation

flowchart TD
    USER["User"]
    REDIS["Redis Cache"]
    OLD["Returns Old Data"]
    DB["Database"]
    NEW["Database Has New Data"]

    USER --> REDIS
    REDIS --> OLD

    DB --> NEW

Users receive outdated information.


With Cache Invalidation

flowchart TD
    CLIENT["Update Request"]
    APP["Spring Boot"]
    DB["Update Database"]
    CACHE["Invalidate Redis Cache"]
    READ["Next Read Request"]
    REDIS["Reload Redis Cache"]

    CLIENT --> APP
    APP --> DB
    DB --> CACHE
    CACHE --> READ
    READ --> REDIS

Cache Lifecycle

flowchart TD
    REQ["Client Request"]
    CACHE{"Cache Hit?"}
    DB["Database"]
    STORE["Store in Redis"]
    RESP["Return Response"]

    REQ --> CACHE
    CACHE -- "Yes" --> RESP
    CACHE -- "No" --> DB
    DB --> STORE
    STORE --> RESP

Eventually,

the data changes,

requiring cache invalidation.


Stale Cache Example

Current Product

Laptop

↓

$1200

Administrator changes

Laptop

↓

$999

Database

$999

Redis

$1200

Result

Customers see the old price.


Cache Invalidation Flow

sequenceDiagram

participant Admin

participant SpringBoot

participant PostgreSQL

participant Redis

Admin->>SpringBoot: Update Product

SpringBoot->>PostgreSQL: Save Product

SpringBoot->>Redis: Delete Cache

SpringBoot-->>Admin: Success

The next read recreates the cache.


Strategy 1 - Time To Live (TTL)

The simplest strategy.

Every cache entry expires automatically.

Product

↓

TTL

↓

30 Minutes

After expiration,

Redis removes the entry.

Advantages

  • Simple
  • Automatic

Disadvantages

  • Stale data may remain until expiration.

TTL Flow

flowchart TD
    CACHE["Redis Cache Entry"]
    TTL["TTL Timer"]
    CHECK{"TTL Expired?"}
    DELETE["Delete Cache Entry"]
    ACTIVE["Keep Cache Entry"]

    CACHE --> TTL
    TTL --> CHECK
    CHECK -- Yes --> DELETE
    CHECK -- No --> ACTIVE

Strategy 2 - Explicit Cache Deletion

Whenever the database changes,

delete the cache immediately.

flowchart TD
    CLIENT["Update Request"]
    APP["Spring Boot"]
    DB["Update Database"]
    CACHE["Delete Redis Key"]
    READ["Next Read Request"]
    RELOAD["Reload Cache from Database"]

    CLIENT --> APP
    APP --> DB
    DB --> CACHE
    CACHE --> READ
    READ --> RELOAD

This is the most common approach used with the Cache Aside pattern.


Strategy 3 - Update Cache

Instead of deleting,

update Redis immediately.

flowchart TD
    CLIENT["Client Request"]
    APP["Spring Boot"]
    DB["Update Database"]
    REDIS["Update Redis Cache"]
    SUCCESS["Return Success"]

    CLIENT --> APP
    APP --> DB
    DB --> REDIS
    REDIS --> SUCCESS

This approach is common in Write Through caching.


Strategy 4 - Event-Driven Invalidation

In distributed systems,

one service updates data,

while many services use the cache.

An event notifies everyone to invalidate.

flowchart LR
    PRODUCT["Product Service"]
    KAFKA["Kafka Topic"]

    INVENTORY["Inventory Service"]
    PRICING["Pricing Service"]
    SEARCH["Search Service"]

    REDIS["Redis Cache"]

    PRODUCT --> KAFKA

    KAFKA --> INVENTORY
    KAFKA --> PRICING
    KAFKA --> SEARCH

    INVENTORY --> REDIS
    PRICING --> REDIS
    SEARCH --> REDIS

Benefits

  • Decoupled architecture
  • Better scalability

Strategy 5 - Version-Based Cache

Store a version number with cached data.

Example

Product

Version 5

After update

Version 6

Requests using the old version are ignored.

Useful for:

  • CDN
  • Static Assets
  • APIs

Cache Key Versioning

product:100:v1

↓

product:100:v2

Old cache becomes obsolete automatically.


Redis Architecture

flowchart TD
    USERS["Users"]
    LB["Load Balancer"]

    APP1["Spring Boot Instance 1"]
    APP2["Spring Boot Instance 2"]

    REDIS["Redis Cluster"]
    DB["PostgreSQL"]

    USERS --> LB
    LB --> APP1
    LB --> APP2

    APP1 --> REDIS
    APP2 --> REDIS

    REDIS --> DB

Redis stores temporary cached data.

The database remains the source of truth.


Spring Boot Flow

flowchart TD
    CLIENT["Client"]
    APP["Spring Boot API"]
    DB["Update PostgreSQL"]
    CACHE["Invalidate Redis Cache"]
    RESPONSE["Return Success"]

    CLIENT --> APP
    APP --> DB
    DB --> CACHE
    CACHE --> RESPONSE

The next read recreates the cache with fresh data.


Banking Example

Cache

  • Branch Details
  • Exchange Rates
  • Interest Rates

Do Not Cache

  • Account Balance
  • Payment Status
  • Transaction History

If an interest rate changes,

the cached value should be invalidated immediately.


Amazon Example

Product

Price

Inventory

Reviews

If the price changes,

Redis entries are invalidated,

ensuring customers always see the latest value.


Netflix Example

When a movie title or thumbnail changes,

metadata caches are refreshed across multiple regions.


Uber Example

Driver Location

Latitude

Longitude

These values change frequently.

TTL values are intentionally very short to avoid stale locations.


Cache Invalidation Strategies Comparison

Strategy Best Use Case
TTL Frequently changing data
Explicit Delete Cache Aside
Update Cache Write Through
Event Driven Microservices
Versioning Static Assets & APIs

Cache Invalidation vs Cache Eviction

Cache Invalidation Cache Eviction
Triggered by data changes Triggered by memory limits
Removes stale data Frees memory
Focuses on consistency Focuses on capacity

Monitoring

Monitor

  • Cache Hit Ratio
  • Cache Miss Ratio
  • Invalidated Keys
  • TTL Expirations
  • Stale Reads
  • Redis Memory Usage
  • Database Queries
  • Cache Refresh Latency

Tools

  • Redis Insight
  • Datadog
  • Prometheus
  • Grafana
  • CloudWatch

Common Mistakes

❌ Forgetting to invalidate cache after updates

❌ Very long TTL values

❌ Updating the database without updating Redis

❌ Caching rapidly changing transactional data

❌ Using Redis as the source of truth

❌ No monitoring for stale data


Best Practices

  • Use explicit invalidation for critical business data.
  • Configure TTL based on how frequently data changes.
  • Use event-driven invalidation in microservices.
  • Keep cache keys simple and consistent.
  • Version cache keys for static assets and APIs.
  • Monitor stale cache occurrences.
  • Automate cache refresh after updates.
  • Use Redis as a cache—not the primary database.

Common Interview Questions

What is Cache Invalidation?

Cache Invalidation is the process of removing or updating outdated cache entries after the underlying data changes.


Why is Cache Invalidation difficult?

Because cached data exists separately from the database. Keeping both synchronized across distributed systems without sacrificing performance is challenging.


What is the most common Cache Invalidation strategy?

For applications using the Cache Aside pattern, the most common strategy is to update the database and immediately delete the corresponding Redis key so that the next read reloads fresh data.


What is the difference between Cache Invalidation and Cache Eviction?

Cache Invalidation ensures stale data is removed after updates, whereas Cache Eviction removes entries to free memory when the cache reaches capacity.


When should TTL be used?

TTL works well for data that changes periodically and where a small amount of temporary staleness is acceptable, such as product catalogs, exchange rates, or reference data.


Summary

Cache Invalidation is one of the most important aspects of building reliable caching systems. Without it, applications risk serving stale or incorrect data, even when the database contains the latest information.

In this article, we covered:

  • Cache Invalidation fundamentals
  • Cache lifecycle
  • Stale cache
  • TTL
  • Explicit cache deletion
  • Write Through updates
  • Event-driven invalidation
  • Version-based invalidation
  • Redis integration
  • Spring Boot architecture
  • Banking, Amazon, Netflix, and Uber examples
  • Monitoring
  • Best practices

A well-designed cache invalidation strategy ensures that applications achieve both high performance and data consistency, making it a critical component of enterprise-scale distributed systems.


Loading likes...

Comments

Share a question, correction, or practical insight about this article.

Loading approved comments...