快取有一個很陰的特性:它壞掉的時候不會報錯。

DB 掛了你馬上知道(整片 500);快取「壞了」——命中率從 95% 掉到 40%——系統照常出貨,只是每個請求多繞一趟沒用的快取、DB 默默多扛好幾倍流量。等你發現的時候,通常是 DB 先撐不住了,而你還在 DB 那邊找原因。

更難堪的一種:快取根本從來沒發揮過作用。key 設計錯了永遠 miss、或快取了一堆沒人重複讀的東西——每個請求都白付一次網路來回,比不裝快取還慢。沒有監控,這種「負資產快取」可以安靜地跑好幾年。

所以這篇只有一個主張:快取上線的那天,監控要一起上線。要看的就三個數字。


三個必看指標

一、命中率(hit rate)。 Redis 的 INFO stats 裡有兩個累計值:keyspace_hitskeyspace_misses,命中率 = hits ÷ (hits + misses)。這是快取的成績單——它到底幫 DB 擋掉了幾成的讀?

健康值看場景,但有兩條經驗線:讀多寫少的業務快取長期低於九成,值得查;低於五成,這個快取很可能是負資產,擋掉的 DB 查詢抵不過多付的來回成本。

注意 INFO 給的是「開機以來的累計」,看趨勢要靠外部定期抓、算差值——這正是 exporter 的工作(下面講)。

二、淘汰數(evicted_keys)。 這個數字在漲 = 記憶體滿了、Redis 正在照淘汰策略丟東西。它跟命中率是連動的:東西被提早踢掉 → 本來會命中的變 miss → 命中率下滑。看到命中率跌,先看 eviction——很多「快取變差」其實是「記憶體不夠」。

三、記憶體水位(used_memory / maxmemory)。 eviction 的先行指標。水位長期在九成以上,eviction 遲早開始;搭配 MEMORY USAGE 抽查大 key,可以在事故前找到吃記憶體的大戶。


去哪撈:從 INFO 到 Grafana

臨時看,redis-cli INFO statsINFO memory 就有全部原料;redis-cli --stat 是每秒刷新的即時儀表。

長期看,標配是 redis_exporter + Prometheus + Grafana:exporter 定期抓 INFO 轉成 metrics,你就有了命中率曲線、eviction 速率、記憶體水位的時間序列——「命中率這三週從 93% 緩慢滑到 78%」這種慢性病,只有曲線看得出來,任何單次查看都看不出來。

再進一階是應用端自己打 metrics:在 CacheService 那層對每次 get 記 hit/miss(帶上 key 的類別標籤)。Redis 端的命中率是全局平均,應用端的能告訴你「是哪一類 key 在拖低命中率」——排查的時候,這個粒度差很多。


命中率低,四種病因怎麼分

看到命中率難看,照這個順序排查:

  1. TTL 太短——資料還沒被讀幾次就過期了。特徵:miss 率高但 eviction 不高。把主力 key 的 TTL 拉長試試。
  2. 記憶體不夠、淘汰太兇——特徵:evicted_keys 持續在漲。加記憶體,或先用 MEMORY USAGE 找大 key 瘦身。
  3. key 設計錯誤——key 裡混進了每次都不同的成分(時間戳、隨機值、完整 query string),同樣的資料每次都是「新 key」,永遠 miss。特徵:key 總數暴漲但每個 key 只被讀一次。
  4. 快取了不會被重複讀的東西——每個使用者只看自己一次的資料、一次性的報表。這不是調參能救的,是「這東西根本不該快取」(見同系列 #26 反模式)。

[作者補:一次靠命中率曲線抓到問題、或發現負資產快取的實際經驗]


一句收束:快取的失敗模式是「安靜地變糟」,監控是唯一的煙霧偵測器。 命中率、eviction、記憶體水位三條曲線畫起來,再把應用端的 hit/miss 按 key 類別拆開——之後每一次「快取好像怪怪的」,你都有證據可以直接翻,而不是猜。

(工具本身的用法——INFO/SLOWLOG/MEMORY USAGE/exporter——見同系列 #27。)

接下來往哪走