User Tools

Site Tools


skills:cache

This is an old revision of the document!


Cache Invalidation Patterns in Real Production Systems

Overview

Cache invalidation ensures cached data stays consistent with the database in distributed systems.

In real production systems, the hardest problem is:

Keeping cache correct under concurrency and distributed timing issues.

Most systems use hybrid strategies, not a single pattern.

1. Cache-Aside (Most Common Pattern)

Concept

Application manages cache manually. Cache is disposable; DB is source of truth.

Read Flow

 Client → Application → Cache ↓ miss Database → Cache → Response 

Write Flow

 Client → Application → Database update → delete cache key 

Where it is used

E-commerce systems Microservices APIs Social platforms

Pros

Simple Safe Easy to debug

Cons

First read after miss is slow Small stale window possible 2. Write-Through Cache

Concept

Write goes through cache first, then DB.

Flow

 Client → Cache → Database 

Pros

Strong consistency No stale cache

Cons

Slower writes Higher cost 3. Write-Behind Cache

Concept

Write goes to cache first, DB updated asynchronously.

Flow

 Client → Cache (ACK) ↓ async Database 

Pros

Very fast writes High throughput

Cons

Risk of data loss Complex recovery 4. TTL-Based Invalidation

Concept

Cache expires automatically after time.

Example

 user:123 → TTL = 5 minutes 

Pros

Simple Safe fallback mechanism

Cons

Stale data until expiry 5. Event-Driven Invalidation

Concept

DB changes trigger events that invalidate cache.

Flow

 Service → Database update → Event (UserUpdated) ↓ Cache Service → delete/update cache 

Pros

Decoupled architecture Scales well

Cons

Eventual consistency Event delay or loss possible 6. Critical Concept: Update-on-write vs Invalidate-on-write (Concurrency) 🟥 6.1 Update-on-write (RISKY in concurrency)

Problem

When multiple requests update same data concurrently, cache can become inconsistent due to race conditions.

Scenario

Request A updates value = “A” Request B updates value = “B”

Sequence Diagram

 Client A Go API DB Redis | | | | |---update A--->| | | | |---UPDATE--->| | | |<--OK--------| | | |---SET A------------------->| | | | |

Client B Go API DB Redis
| | | |
|---update B--->| | |
| |---UPDATE--->| |
| |<--OK--------| |
| |---SET B------------------->|

Problem

If timing is reversed:

DB: A → B (correct) Redis: A overwrites B (wrong)

Result:

DB = “B” (correct) Cache = “A” (stale ❌)

Conclusion

Update-on-write is unsafe because:

Race condition Out-of-order execution Distributed timing inconsistency 🟩 6.2 Invalidate-on-write (SAFE approach)

Concept

Do NOT update cache. Only delete it.

Sequence Diagram

 Client A Go API DB Redis | | | | |---update A--->| | | | |---UPDATE--->| | | |<--OK--------| | | |---DEL cache--------------->| | | | |

Client B Go API DB Redis
| | | |
|---update B--->| | |
| |---UPDATE--->| |
| |<--OK--------| |
| |---DEL cache--------------->|

Why it is safe

Even if requests are out of order:

Cache only gets deleted multiple times No stale value is written into cache

Read Flow

 Client → Redis (miss) → DB → set cache 

Always consistent with DB.

7. Comparison Table Aspect Update-on-write Invalidate-on-write Cache operation SET DELETE Race condition risk ❌ High ✅ Low Out-of-order issue ❌ Dangerous ❌ Safe Debug complexity Hard Easy Consistency Fragile Reliable 8. Key Insight

Cache is not the source of truth.

DB = truth Cache = disposable optimization layer

Invalidate-on-write works because:

“Even if cache is wrong, it gets deleted anyway”

9. Production Pattern (Real Systems)

Most real systems use:

 WRITE: 1. Update DB 2. Delete Redis key

READ:
Cache hit → return
Cache miss → DB → set cache

10. Why update-on-write still exists

Used only when:

Simple data (low concurrency) Need ultra-fast read-after-write No complex cache relationships

Examples:

Session storage Feature flags Simple counters

skills/cache.1779778599.txt.gz · Last modified: by phong2018