在系統架構中,快取 (Caching) 是一把雙面刃。它能讓你的系統快如閃電,也可能導致災難性的錯誤。關鍵不在於「如何」快取,而在於「何時」與「何物」該快取。本文將提供一套實用的決策流程,靈感源自許多工程師在白板上草擬的思路,幫助您做出明智的快取決策。
快取決策樹:七個關鍵問題
在決定是否使用快取前,請依序回答以下問題:
1. 資料存取頻繁嗎?
* 否:請勿快取。避免不必要的複雜性。
* 是:進入下一問題。
2. 資料取得成本高昂嗎?
* 這包括緩慢的資料庫查詢、呼叫外部 API,或大量的計算。
* 否:仍不建議快取。系統瓶頸不在此處。
* 是:進入下一問題。
3. 資料的穩定性如何?
* 穩定:這是絕佳的快取候選。若資料體積龐大或結構複雜,可考慮「部分快取」,例如快取預先計算好的彙總值或查詢結果的特定欄位。
* 易變:只有在您能可靠地讓快取失效時,才應考慮快取。若無法確保失效機制的正確性,請放棄快取,因為「正確性」遠比「速度」重要。若有可靠的失效機制,可採用短的存活時間 (TTL) 或事件驅動的失效策略。
4. 是否影響使用者體驗 (UX) 或關鍵內部效能?
* 否:除非是為了解決繁重的內部批次處理任務,否則應避免快取。
* 是:進入下一問題。
5. 快取資料是否安全?
* 這涉及個人可識別資訊 (PII)、多租戶架構的資料邊界、權限範圍等敏感資訊。
* 否:絕對不能快取原始的敏感資料。應考慮使用範圍限定或加密的金鑰、移除敏感欄位,或只快取衍生出的非敏感結果。
* 是:進入下一問題。
6. 系統能否規模化 (Scale)?
* 考量快取金鑰的基數(cardinality,即金鑰的數量)、記憶體用量與淘汰策略,以及快取失效時可能引發的「驚群效應」(Dogpile Effect)。 [[1]](https://www.qiankun.info/posts/%E6%83%8A%E7%BE%A4%E6%95%88%E5%BA%94/)[[2]](https://cloud.tencent.com/developer/article/2434114)
* 否:您需要重新設計方案。例如透過分片 (Shard)、預先計算、批次處理或引入寫入型儲存來解決。
* 是:✅ 恭喜!可以進行快取。
常見快取模式
當您決定快取後,以下幾種模式可供參考:
* 旁路快取 (Cache-aside / Lazy Loading):應用程式先讀取快取,若未命中 (miss),則從資料來源讀取,再寫入快取。 [[3]](https://blog.csdn.net/LearnerDL/article/details/137610941)[[4]](https://coolshell.cn/articles/17416.html) 這是最常見的模式,簡單且靈活。
* 寫入穿透 (Write-through):更新資料時,同時寫入資料庫和快取。 [[5]](https://benjr.tw/20361)[[6]](https://jason2506.gitbooks.io/cpumemory/content/cpu-caches/cpu-cache-implementation-details/write-behavior.html) 這種模式能提供較強的一致性,但會增加寫入延遲。
* 寫入後更新 (Write-behind):先將寫入操作放入緩衝區,再非同步更新資料庫。此模式大幅提升寫入吞吐量,但需要額外的機制來確保資料在系統崩潰時不會遺失。
* 過期時重新驗證 (Stale-while-revalidate):立即提供稍微過期的舊資料給使用者,並在背景非同步更新快取。 [[7]](https://web.dev/articles/stale-while-revalidate?hl=zh-tw)[[8]](https://www.kelen.cc/posts/stale-while-revalidate) 對於穩定性高的資料,這能提供極佳的使用者體驗。
TTL 與失效策略快速指南
* 高度穩定的內容:例如文章或設定檔,TTL 可設定為數小時至數天,並在每次部署或版本更新時手動清除。
* 中度動態的列表:例如商品列表,TTL 可設為數分鐘,並搭配 Stale-while-revalidate 策略以提供流暢體驗。 [[7]](https://web.dev/articles/stale-while-revalidate?hl=zh-tw)[[8]](https://www.kelen.cc/posts/stale-while-revalidate)
* 高度易變的資料:例如即時庫存、價格或計數器,最好使用事件驅動的失效機制,或將 TTL 設為數秒。在極端情況下,可考慮將 Redis 這類高速記憶體儲存作為主要資料來源,並定期快照回永久儲存。
提示:務必在快取金鑰中包含版本號(如 v3:),以便在資料結構或業務邏輯變更後,能一次性讓所有相關的舊快取失效。
維運與安全檢查清單
* 監控指標:追蹤快取命中率、p95 延遲、淘汰次數以及對原始資料來源的負載。
* 安全提示:
* 根據租戶、使用者、地區或功能旗標來劃分金鑰範圍,例如 inv:v3:tenant:{id}:list?status=overdue。
* 絕不快取原始的密碼或個人可識別資訊 (PII)。只快取 ID 或渲染後的視圖。
* 考慮使用「請求合併」(Request Coalescing) 機制,避免在快取失效時,大量請求同時穿透到後端資料庫,引發「驚群效應」。 [[1]](https://www.qiankun.info/posts/%E6%83%8A%E7%BE%A4%E6%95%88%E5%BA%94/)[[2]](https://cloud.tencent.com/developer/article/2434114)
* 可靠性:
* 確保在快取服務不可用或冷啟動時,系統能優雅降級。
* 在資料來源周圍實作熔斷器 (Circuit Breakers),並建立防止驚群效應的保護機制。
實例應用
* 產品目錄頁面:讀取密集、涉及複雜的資料庫關聯,且每小時更新。適合採用旁路快取,TTL 設為 5-10 分鐘,搭配 SWR 和事件觸發失效。
* 使用者儀表板總計:高成本的彙總計算,且因人而異。可透過夜間批次任務預先計算結果並進行部分快取,使用範圍限定金鑰,TTL 設為 15-30 分鐘。
* 即時庫存:高度易變。優先考慮事件驅動的失效機制或直接使用高速主儲存。若要快取,TTL 應設為秒級,並配合請求合併來更新。
結語
如果所有東西都被快取,那沒有什麼是可靠的;如果什麼都不快取,那沒有什麼是快速的。請善用這份決策指南,優先保護資料的正確性,然後在真正重要的地方,用快取換取更低的延遲。