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.
Comments
Share a question, correction, or practical insight about this article.
Checking login status...
Loading approved comments...