結論先講

Cache 出問題時比沒有 cache 更糟。 沒有 cache 頂多是慢,cache 出 bug 是「看到舊資料」「付了錢但顯示沒付」「庫存顯示有但下單說沒有」。這些 bug 比效能問題更難查、更難修、更讓用戶生氣。


誤用一:什麼都往 Redis 塞

症狀

// 每個 API endpoint 都加 cache
app.get('/api/users/:id', cache('user', 300), getUser);
app.get('/api/orders/:id', cache('order', 300), getOrder);
app.get('/api/products/:id', cache('product', 300), getProduct);
app.get('/api/cart/:id', cache('cart', 300), getCart);
app.get('/api/notifications', cache('notif', 60), getNotifications);

看起來很勤勞。但 cart 和 notifications 每次都不一樣(用戶剛加了商品、剛收到通知),cache hit rate 趨近於零。你付出了 Redis roundtrip 的成本(每次查 Redis 再查 DB),效能反而更差。

怎麼修

只 cache 讀取頻繁 + 很少變動 的資料。上一篇 的表格是判斷依據。在加 cache 之前先問:「這個 endpoint 的 cache hit rate 預期是多少?」低於 50% 就不值得。


誤用二:Cache Key 沒有 Namespace

症狀

// Service A: cache user profile
redis.set(`user:${userId}`, profileData);
 
// Service B: cache user permissions
redis.set(`user:${userId}`, permissionData);  // 覆蓋了 A 的資料!

兩個 service 用了同一個 key pattern user:{id},互相覆蓋。

怎麼修

// 加 namespace
redis.set(`profile-service:user:${userId}`, profileData);
redis.set(`auth-service:user:${userId}`, permissionData);

命名規則:{service}:{entity}:{id}:{field?}


誤用三:部署後 Cache 是空的

症狀

部署新版本 → Redis 被 flush(或 key 結構改了)→ 所有請求都 cache miss → 全部打 DB → DB 扛不住 → 服務掛掉。

這就是 上一篇 講的 cache stampede,但觸發原因是「部署」而不是「TTL 過期」。

怎麼修

1. 部署時不要 flush Redis

除非 cache 的資料結構改了,否則讓舊 cache 慢慢過期,不要一次清空。

2. Cache Warmup Script

部署完成後,自動跑一次 warmup——查出熱門資料寫入 Redis,在真實流量進來之前把 cache 填好。

// warmup.js — 部署後自動執行
const hotProducts = await db.query('SELECT * FROM products ORDER BY views DESC LIMIT 1000');
for (const p of hotProducts) {
  await redis.set(`product:${p.id}`, JSON.stringify(p), 'EX', 3600);
}

3. 限流

部署後的前幾分鐘開啟更積極的 rate limiting,減少 DB 被 cache miss 打爆的風險。


誤用四:Cache 比 DB 還大

症狀

「為了效能」把每次查詢結果都 cache,包含帶有大量 JOIN 的查詢結果。一筆 cache entry 500KB,10 萬筆 = 50GB。Redis 的 RAM 用量超過 DB。

怎麼修

  1. 只 cache 必要的欄位,不是整個查詢結果
  2. 設合理的 TTL,不要永不過期
  3. 監控 Redis 記憶體使用redis-cli INFO memory
  4. 設 maxmemory + eviction policymaxmemory 2gb + maxmemory-policy allkeys-lru

誤用五:不知道 Cache 在 Cache 什麼

症狀

系統慢 → 有人說「加 cache」→ 隨便包一層 Redis → 效能沒改善但沒人敢拆(怕拆了更慢)。

三個月後,沒人記得哪些 endpoint 有 cache、TTL 是多少、什麼時候 invalidate。新來的工程師改了資料但畫面不更新,查了兩天才發現「有一層不知道誰加的 cache」。

怎麼修

Cache 要有文件。 至少要紀錄:

Key PatternTTLInvalidation 時機負責 Service
product:{id}15min商品更新時刪product-service
post-list:page:{n}5min新文章發布時刪post-service
user-session:{token}60min登出時刪auth-service

沒有文件的 cache = 技術債。


下一篇

Event-Driven 架構入門:為什麼微服務離不開它 — 單體用 function call,微服務用 event。不是因為潮,是因為你沒辦法跨服務做 transaction。從「為什麼需要」到「怎麼設計 event schema」。


本系列文章

完整 68 篇目錄見 系列首頁

← 上一篇:Cache 的正確用法:不是什麼都往 Redis 塞 → 下一篇:Event-Driven 架構入門:為什麼微服務離不開它