Caching
Strategies
The fastest network request is the one you don't make. Caching is borrowing RAM from the future to pay for the latency of the past.
Why We Cache
Temporal Locality
"If I just read this data, I'm likely to read it again soon."
Spatial Locality
"If I read this data, I'm likely to read its neighbors soon."
Caching Patterns
Cache-Aside (Lazy Loading)
The application is responsible for reading and writing to the cache. The cache doesn't know about the database.
- App checks Cache.
- If Miss: App reads DB.
- App writes to Cache.
- App returns data.
- Only requested data is cached.
- Cache failure doesn't kill the app (just slower).
- Cache Miss penalty (3 trips).
- Stale data if DB updates without cache invalidation.
Write-Through
App writes to the Cache, and the Cache synchronously writes to the DB.
- App writes data to Cache.
- Cache writes to DB.
- Both return success.
- Data in cache is never stale.
- Read performance is excellent.
- Write latency is higher (2 writes).
- Cache pollution (writing data that's never read).
Write-Back (Write-Behind)
App writes to Cache and returns immediately. Cache asynchronously writes to DB later.
- App writes to Cache.
- App gets "Success".
- Cache updates DB in background.
- Lowest write latency.
- Good for write-heavy workloads.
- Data Loss Risk: If cache crashes before DB sync.
- Complex implementation.
Eviction Policies
Cache memory is expensive and finite. When it's full, who gets kicked out?
LRU
Most CommonLeast Recently Used
Discards the item that hasn't been used for the longest time.
Good for: General purpose, Recency bias.
LFU
Usage BasedLeast Frequently Used
Counts how often an item is needed. Kicks out the unpopular ones.
Good for: Stable access patterns.
FIFO
SimpleFirst In First Out
Oldest item leaves first, regardless of usage.
Good for: Sequential data.
TTL
Time BasedTime To Live
Items expire after a set time (e.g., 5 mins).
Good for: Data that must be fresh (prices, inventory).
The Thundering Herd
The Scenario
A popular cache key expires (or cache server crashes). Suddenly, 10,000 requests hit the cache at the same time, get a MISS, and ALL hit the Database simultaneously.
The Fixes
Don't expire all keys at exactly 5:00 PM. Add jitter (e.g., 5 min ± 30s).
If 100 requests want key 'A', let one go to DB, making the other 99 wait for that result.
Distributed Caching
When your cache is bigger than one server's RAM, you need a cluster (Redis Cluster, Memcached).
How to find the key?
If you have 5 cache servers, where does key "user_123" live?
Bad because adding a server breaks 100% of mappings.
Good! Adding a server only reshuffles 1/N keys.
Redis vs Memcached
- RedisSingle-threaded event loop. Supports complex data structures (Lists, Sets, Sorted Sets). Persistence options.
- MemcachedMulti-threaded. Pure Key-Value store. Simple, extremely high throughput for simple strings.