Implementing Caching Strategies
1. Using Cache-Aside Pattern
| Step | Action |
|---|---|
| 1 | App reads from cache |
| 2 | Miss → query DB |
| 3 | Populate cache with TTL |
| 4 | Return value |
Example: Lookup with cache-aside
String v = jedis.get(key);
if (v == null) {
v = db.load(key);
jedis.setex(key, 300, v);
}
return v;
2. Using Write-Through Pattern
| Aspect | Detail |
|---|---|
| Write order | App → cache → DB synchronously |
| Consistency | Strong; both updated atomically (app responsibility) |
| Latency | Higher write latency |
3. Using Write-Behind Pattern
| Aspect | Detail |
|---|---|
| Write order | App → cache; async flush to DB |
| Tradeoff | Fast writes, risk of data loss on crash |
| Use case | Counters, metrics, non-critical writes |
4. Implementing TTL-Based Expiration
| Pattern | Command |
|---|---|
| Set + TTL | SET key v EX 300 |
| Refresh on read | GETEX key EX 300 |
| Sliding window | Reset TTL on each access |
5. Handling Cache Invalidation
| Strategy | Description |
|---|---|
| Delete on write | App DELs cache key after DB update |
| TTL-only | Eventual consistency via short TTL |
| Pub/Sub fanout | Broadcast invalidation to nodes |
| Client-side tracking | RESP3 invalidation messages 6.0+ |
6. Using Probabilistic Early Expiration
Example: XFetch algorithm
// recompute early with probability ∝ (β × delta × log(rand))
double rnd = Math.log(Math.random());
if (now - lastWrite + beta * recomputeMs * rnd >= expiry) {
refreshCache();
}
| Benefit | Description |
|---|---|
| Stampede prevention | Spreads recomputation in time |
7. Implementing Cache Warming
| Strategy | When |
|---|---|
| Startup load | Pre-populate hot keys on boot |
| Background refresh | Scheduled job rehydrates top-N items |
| Pipelined MSET | Bulk warm via single round-trip |
8. Preventing Cache Stampede
| Technique | Description |
|---|---|
| Lock + recompute | SET NX lock; only winner rebuilds |
| Stale-while-revalidate | Serve old value while refreshing |
| Probabilistic early | XFetch algorithm |
| Request coalescing | Per-process singleflight |
9. Using Lazy Loading
| Property | Detail |
|---|---|
| Trigger | Populate only on miss |
| Pro | Cache contains only what's used |
| Con | First request always slow |
10. Implementing Cache Key Patterns
| Pattern | Example |
|---|---|
| Entity | user:42 |
| Compound | user:42:orders |
| Hashtag (Cluster) | {user:42}:orders |
| Versioned | user:42:v3 |
| Namespaced | app:env:type:id |
11. Using Cache Tagging
| Approach | Implementation |
|---|---|
| Tag → keys | SET of keys per tag |
| Invalidate | SMEMBERS tag → UNLINK keys → DEL tag |
12. Implementing Cache Versioning
| Strategy | Detail |
|---|---|
| Counter key | INCR app:cache:version for global purge |
| Prefix key | Include version in cache key — old keys expire naturally |