Caching Strategies: Patterns for Performance
Caching Strategies: Patterns for Performance
A caching strategy (or caching pattern) defines the relationship between the data source and the cache. How do you keep the cache updated? When do you write to it? The choice depends on your application's read/write ratio and consistency requirements.
1. Cache-Aside (Lazy Loading)
This is the most common pattern. The application first checks the cache.
- Read: App checks cache. If hit, return. If miss, fetch from DB, save to cache, and return.
- Write: App writes to DB directly and then invalidates (deletes) the cache entry.
- Pros: Resilient to cache failures (app just hits DB); only caches what is actually requested.
- Cons: First request after an update is always a cache miss (higher latency).
2. Read-Through
The application treats the cache as the main data store. The cache itself is responsible for fetching data from the DB if it's missing.
- Pros: Simplifies application code; data is always "cached" before it reaches the app.
- Cons: Requires a custom cache provider that knows how to talk to your DB.
3. Write-Through
The application writes data to the cache, and the cache synchronously writes it to the database.
- Pros: Data in the cache is never stale; high consistency.
- Cons: Higher write latency (since it waits for both cache and DB).
4. Write-Back (Write-Behind)
The application writes data to the cache and returns immediately. The cache writes the data to the database in the background (asynchronously) after a delay.
- Pros: Extremely low write latency; can batch multiple writes to the DB.
- Cons: Risk of data loss if the cache server crashes before the background write completes.
5. Write-Around
Data is written directly to the database, bypassing the cache. Only subsequent reads will populate the cache (similar to Cache-Aside).
- Pros: Prevents "polluting" the cache with data that is written but rarely read (e.g., archived logs).
- Cons: Higher latency for the first read of a newly written record.
Implementing the Cache-Aside Pattern
- 1Step 1
When a request for
user:123arrives, generate a cache key:cache_key = "user_profile:123". - 2Step 2
Attempt to fetch the value from your cache (e.g., Redis).
profile = redis.get(cache_key). Ifprofileis not null, return it immediately (Cache Hit). - 3Step 3
If the cache returns null (Cache Miss), query your primary database.
profile = db.query("SELECT * FROM users WHERE id=123"). - 4Step 4
Save the database result back into the cache with an appropriate TTL.
redis.set(cache_key, profile, expire=3600). This ensures the next request will be a hit. - 5Step 5
When the user updates their profile, write the change to the database first, then immediately delete the cache key.
db.save(profile); redis.del(cache_key);. This forces the next read to fetch the fresh data.
Choosing the Right Strategy
| Strategy | Read Latency | Write Latency | Consistency | Best For |
|---|---|---|---|---|
| Cache-Aside | Low (Hit) / High (Miss) | Medium | Eventual | General purpose, read-heavy |
| Write-Through | Low | High | Strong | Critical data needing consistency |
| Write-Back | Low | Very Low | Low | High-volume writes (logging, metrics) |
| Write-Around | High (First Read) | Medium | Eventual | Bulk data that isn't read often |
Common Mistakes
- Write-Back Data Loss: Using Write-Back for financial transactions. If the cache server loses power, the transaction is gone forever.
- Stale Cache on Update: Updating the database but forgetting to invalidate the cache entry.
- Cache Invalidation Storms: Deleting thousands of keys at once, causing a sudden spike in database traffic (Thundering Herd).
Recap
- Cache-Aside is the "safe" default for most applications.
- Write-Back is for extreme write performance but carries data loss risk.
- Write-Through ensures strong consistency at the cost of write speed.
- Always match your strategy to your read/write ratio.
Knowledge Check
In which caching strategy does the application write data ONLY to the cache, with the cache handling the database update later in the background?