快取
在慢的資料庫前面放一層快的記憶體。因為熱門資料通常很集中,小小的快取就能擋掉大部分的讀取。
程式碼路徑
1.0
100 (10%)
淘汰策略
命中率(s = 1.0)每個鍵一樣熱門(s = 0)
每 100 次讀取
58 快取
42 資料庫
命中率
57.8%
平均延遲
4.7 ms
p99 延遲
11 ms
每千次讀取打到資料庫
422
假設快取讀一次 0.5 ms、資料庫讀一次 10 ms。對 1,000 個鍵讀 20,000 次;前 4,000 次用來暖機,不計入。
快取只放得下 10% 的鍵,卻接住了 58% 的讀取。熱度這麼集中時(s = 1.0),大家都在讀的那一小撮資料放得進小小的快取;如果每個鍵一樣熱門(s = 0),快取能接住的比例就只等於它裝得下的比例。注意 p99(第 99 百分位):命中率沒超過 99% 之前,最慢的那 1% 讀取還是得去資料庫。
亮起來的是這一步執行的程式碼
interface Database { read(key: string): string; // slow: ~10 ms} class CacheAside { // A Map remembers insertion order: first key = least recently used. private cache = new Map<string, string>(); constructor(private capacity: number, private db: Database) {} get(key: string): string { const cached = this.cache.get(key); if (cached !== undefined) { this.cache.delete(key); this.cache.set(key, cached); return cached; } const value = this.db.read(key); if (this.cache.size >= this.capacity) { const oldest = this.cache.keys().next().value!; this.cache.delete(oldest); } this.cache.set(key, value); return value; }}模型假設與範圍
- 這是可重現的教學模型;延遲、容量、故障率與工作負載是設定或樣本,不能直接當作正式系統的效能承諾。
- Cache-aside、LRU 與 Zipf 存取分布;命中和資料庫延遲是設定值。未模擬更新一致性與連線池競爭。
什麼時候用
- 讀遠多於寫、而且熱門資料很集中時:快取只要放得下熱門的那一小撮,就能擋掉大部分讀取。
- 資料稍微舊一點也沒關係時(商品頁、個人檔案、排行榜)。要求每次都讀到最新值的資料不適合快取。
- 計算很貴、結果可以重複使用時:快取的不一定是資料庫的列,也可以是算好的頁面或查詢結果。
和其他主題的關係
- 延伸閱讀
- 一致性雜湊
出現在這些架構裡
時間與空間複雜度(Big O)
| 操作 | 平均 | 最差 |
|---|---|---|
| 讀取:命中 | O(1) | O(1) |
| 讀取:沒命中 再加上一次資料庫讀取——時間主要花在那裡,不在快取 | O(1) | O(1) |
| 淘汰最久沒用的鍵 | O(1) | O(1) |
空間:O(C),C 是快取容量;有序的雜湊表本身就是雜湊表加一條串列
和其他做法比
| 快取 1% 的鍵 | 快取 5% 的鍵 | 快取 10% 的鍵 | 快取 20% 的鍵 | |
|---|---|---|---|---|
| s = 0(一樣熱門) | 1% | 5% | 10% | 20% |
| s = 0.8 | 8% | 27% | 38% | 52% |
| s = 1.0 | 21% | 46% | 58% | 70% |
| s = 1.2 | 41% | 66% | 76% | 84% |
表中是 LRU(Least Recently Used)的命中率:1,000 個鍵、熱度依 Zipf 分佈(第 k 熱門的鍵被讀的機率正比於 1/kˢ),讀 20,000 次、前 4,000 次暖機不計。一般網站流量的 s 大約在 1 附近。淘汰策略裡的 FIFO 是 First In, First Out(先進先出):滿了就丟掉最早放進來的那一筆,不管它最近有沒有被用到。
真實世界裡的它
- Redis、Memcached 放在資料庫前面,就是這裡的 cache-aside。
- CDN 是放在全世界各地的快取;瀏覽器快取是放在你電腦裡的快取。
- CPU 的 L1/L2/L3(第一、二、三層)快取也是同一個道理,只是時間尺度是奈秒。
取捨與陷阱
- 快取失效很難:資料庫更新了,快取裡的舊值什麼時候清?常見做法是寫入時刪除快取,加上 TTL(Time To Live)當保險。
- 驚群效應:熱門的鍵一過期,成千上萬個請求同時落空、同時去打資料庫。要用鎖或提前更新擋住。
- 平均延遲降了,p99 不一定降:只要還有超過 1% 的讀取落空,最慢的那 1% 仍然是資料庫的速度。