- Cache-aside (lazy loading): check cache → miss → fetch DB → write cache → return — pattern phổ biến nhất, code:
const cached = await redis.get(key); if (cached) return JSON.parse(cached); const data = await db.query(...); await redis.setex(key, 300, JSON.stringify(data)); return data. - Write-through: write cache + DB đồng thời — data luôn fresh nhưng write chậm hơn.
- Write-behind: write cache trước, async flush xuống DB — write rất nhanh nhưng risk mất data nếu cache crash.
- Cache invalidation strategies: TTL (đơn giản, chấp nhận stale data), event-based (on update → delete cache key), versioned keys (
user:${id}:v${version}). - TTL chọn sao cho: data thay đổi ít → TTL dài (1 giờ), data thay đổi nhiều → TTL ngắn (30s) hoặc invalidate on write.
- Cache warming: pre-populate cache khi startup để tránh cold start — gọi
warmCache()sau khi server start. - Thundering herd problem: nhiều requests đồng thời hit expired key → tất cả cùng query DB → DB quá tải.
- Fix: probabilistic early expiration (renew cache trước khi hết hạn), mutex lock (chỉ 1 request query DB, còn lại chờ), stale-while-revalidate.
- Lưu ý: cache key collision — luôn dùng namespace
${service}:${resource}:${id}.
- Cache-aside (lazy loading): check cache → miss → fetch DB → write cache → return — the most common pattern; code:
const cached = await redis.get(key); if (cached) return JSON.parse(cached); const data = await db.query(...); await redis.setex(key, 300, JSON.stringify(data)); return data. - Write-through: write to cache and DB simultaneously — data is always fresh but writes are slower.
- Write-behind: write to cache first, async flush to DB — very fast writes but risk of data loss if cache crashes.
- Cache invalidation strategies: TTL (simple, accepts some stale data), event-based (on update → delete cache key), versioned keys (
user:${id}:v${version}). - TTL selection: rarely changing data → long TTL (1 hour); frequently changing data → short TTL (30s) or invalidate on write.
- Cache warming: pre-populate cache on startup to avoid cold start — call
warmCache()after server starts. - Thundering herd problem: many requests simultaneously hit an expired key → all query the DB → DB is overloaded.
- Fix: probabilistic early expiration (renew cache before it expires), mutex lock (only one request queries the DB while others wait), stale-while-revalidate.
Pitfall: cache key collision — always use namespaces ${service}:${resource}:${id}.