快取有一個很陰的特性:它壞掉的時候不會報錯。
DB 掛了你馬上知道(整片 500);快取「壞了」——命中率從 95% 掉到 40%——系統照常出貨,只是每個請求多繞一趟沒用的快取、DB 默默多扛好幾倍流量。等你發現的時候,通常是 DB 先撐不住了,而你還在 DB 那邊找原因。
更難堪的一種:快取根本從來沒發揮過作用。key 設計錯了永遠 miss、或快取了一堆沒人重複讀的東西——每個請求都白付一次網路來回,比不裝快取還慢。沒有監控,這種「負資產快取」可以安靜地跑好幾年。
所以這篇只有一個主張:快取上線的那天,監控要一起上線。要看的就三個數字。
三個必看指標
一、命中率(hit rate)。 Redis 的 INFO stats 裡有兩個累計值:keyspace_hits 和 keyspace_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 stats 加 INFO memory 就有全部原料;redis-cli --stat 是每秒刷新的即時儀表。
長期看,標配是 redis_exporter + Prometheus + Grafana:exporter 定期抓 INFO 轉成 metrics,你就有了命中率曲線、eviction 速率、記憶體水位的時間序列——「命中率這三週從 93% 緩慢滑到 78%」這種慢性病,只有曲線看得出來,任何單次查看都看不出來。
再進一階是應用端自己打 metrics:在 CacheService 那層對每次 get 記 hit/miss(帶上 key 的類別標籤)。Redis 端的命中率是全局平均,應用端的能告訴你「是哪一類 key 在拖低命中率」——排查的時候,這個粒度差很多。
命中率低,四種病因怎麼分
看到命中率難看,照這個順序排查:
- TTL 太短——資料還沒被讀幾次就過期了。特徵:miss 率高但 eviction 不高。把主力 key 的 TTL 拉長試試。
- 記憶體不夠、淘汰太兇——特徵:
evicted_keys持續在漲。加記憶體,或先用MEMORY USAGE找大 key 瘦身。 - key 設計錯誤——key 裡混進了每次都不同的成分(時間戳、隨機值、完整 query string),同樣的資料每次都是「新 key」,永遠 miss。特徵:key 總數暴漲但每個 key 只被讀一次。
- 快取了不會被重複讀的東西——每個使用者只看自己一次的資料、一次性的報表。這不是調參能救的,是「這東西根本不該快取」(見同系列 #26 反模式)。
[作者補:一次靠命中率曲線抓到問題、或發現負資產快取的實際經驗]
一句收束:快取的失敗模式是「安靜地變糟」,監控是唯一的煙霧偵測器。 命中率、eviction、記憶體水位三條曲線畫起來,再把應用端的 hit/miss 按 key 類別拆開——之後每一次「快取好像怪怪的」,你都有證據可以直接翻,而不是猜。
(工具本身的用法——INFO/SLOWLOG/MEMORY USAGE/exporter——見同系列 #27。)
接下來往哪走
- Redis 資料結構 — INFO stats 那兩個數字怎麼來的,指令層在這篇
- Cache Penetration — 低命中率病因之一「快取不到的流量」的完整解剖
- 為什麼「加個 cache」常常讓事情更糟 — 「沒監控 hit rate 等於不知道貸款利率」的出處