題目與情境
你營運 GET /catalog,前面有 CDN 和應用程式快取。部署期間來源站可能變慢,但客戶寧願看到稍舊的目錄,也不想看到空白頁。請設計快取回應標頭和重新驗證路徑,同時隔離租戶資料並讓新鮮度可量測。
假設目錄按租戶公開,寫入經過來源站,緊急價格變更必須很快可見。回答要區分可用性兜底和允許回傳敏感狀態的權限。
面試官在考察什麼
- 是否理解新鮮、過期、重新驗證,以及獨立的
stale-if-error策略。 - 快取鍵是否包含租戶、授權、語言和內容協商邊界。
- 並發 miss 是否只觸發一次來源站請求,而不是驚群。
- 維運能否撤銷過期服務,並用指標證明新鮮度。
作答前的釐清問題
- 回應是公開、租戶級還是使用者級?私有資料可能根本不能放入 CDN 共用快取。
- 正常讀取和來源站故障分別允許多舊?這會形成獨立的新鮮窗口和過期窗口。
- 價格或權限變更能否立即使物件失效?若能,應增加 purge 或版本化鍵,不能只依賴 TTL。
- 是否有驗證器?
ETag或Last-Modified可以把整包刷新變成條件重新驗證。
30 秒回答框架
「我先定義新鮮窗口、有界的 stale-while-revalidate 窗口,以及獨立的 stale-if-error 窗口。快取鍵包含所有表示和授權邊界,使用者資料保持 private。過期命中快速回傳,同時每個鍵只觸發一次背景條件請求,並合併並發 miss。緊急變更透過 purge 或版本化鍵處理。指標涵蓋年齡、重新驗證結果、stale-if-error 使用和租戶洩漏測試,維運可以關閉過期服務。」
分步深入解答
1. 分離新鮮度與可用性
max-age 定義回應保持新鮮的時間。stale-while-revalidate 允許快取過期後在有界時間內先回傳舊回應,同時背景重新驗證。stale-if-error 是來源站報錯時獨立的可用性允許。兩者都不讓舊資料自動正確;存在 must-revalidate 或適用的 no-cache 規則時不能隨意重用。
公開目錄可以使用短新鮮窗口和較長但有界的過期窗口。權限、餘額或緊急價格應使用 private、no-store、purge 路徑或更嚴格策略。窗口由業務風險決定,不由快取預設值決定。
2. 建立安全快取鍵與回應合約
快取鍵必須包含租戶、語言、編碼,以及 Vary 指定的請求標頭。除非表示明確公開且與授權無關,否則不能讓驗證回應進入共用快取。回應可以清楚宣告策略:
Cache-Control: public, max-age=30, stale-while-revalidate=120, stale-if-error=600
Vary: Accept-Encoding, Accept-Language, X-Tenant-ID
ETag: "catalog-tenant-7-v42"伺服器必須確認 X-Tenant-ID 來自驗證路由或 host,而不是任意客戶端值。如果租戶邊界不能安全體現在快取鍵中,就關閉共用快取。
3. 在不驚群的情況下重新驗證
過期命中時回傳已有正文,並為每個快取鍵排隊一次重新驗證。用短鎖或 single-flight 映射,避免一萬次讀取產生一萬次來源站呼叫。重新驗證送出 If-None-Match;304 Not Modified 只刷新新鮮度,新的 200 則替換物件和驗證器。
重新驗證遇到暫時錯誤時,只能在 stale-if-error 邊界內繼續提供舊物件,同時記錄錯誤和年齡。不能每次失敗都重設過期計時器,讓窗口無限延長。
4. 讓失效有明確路徑
TTL 是安全網,不是緊急控制。價格或權限變更應發布版本化失效事件或清除受影響的鍵。寫入路徑可以先提交新版本,再發布事件;消費者需要冪等並支援重播。無法確認 purge 時,可以給受影響租戶附加短 must-revalidate 期,或暫時繞過該鍵快取。
5. 量測並營運策略
追蹤回應年齡、新鮮命中率、stale-while-revalidate 命中率、stale-if-error 次數、重新驗證延遲、304 比率、來源站錯誤率、鎖競爭和快取鍵數量。對年齡接近最大值、stale-if-error 突增和跨租戶測試失敗告警。
提供功能開關或路由級 kill switch 停止回傳過期內容。測試冷 miss、並發過期命中、來源站逾時、驗證器變化、purge 競態、租戶標頭、語言變體和緊急價格更新。測試標準是新鮮度和隔離合約,不只是延遲降低。
高品質示範回答
我先給資料分類。公開的租戶級目錄可以設定 max-age=30、stale-while-revalidate=120 和單獨論證的 stale-if-error=600;使用者或權限資料應保持 private 或不快取。快取鍵包含租戶和表示維度,回應攜帶驗證器。
過期命中時回傳正文,而且每個鍵只做一次條件重新驗證。304 刷新新鮮度,200 替換物件。暫時來源站故障可在有界 stale-if-error 時間內回傳舊值,但不能無限重設計時器。寫入發布冪等 purge 或版本事件處理緊急變更。我會監控年齡、過期使用、驗證結果和租戶隔離,並保留關閉過期服務的開關。
常見失誤
- 錯誤表現:對帳戶或權限資料使用
stale-while-revalidate→ 失敗原因:快速舊回應可能暴露無效授權判斷 → 修正方法:敏感資料保持 private 或不快取。 - 錯誤表現:快取鍵遺漏租戶或語言 → 失敗原因:一個表示可能跨邊界提供 → 修正方法:推導並測試每個鍵維度。
- 錯誤表現:每次失敗重新驗證都重設過期計時器 → 失敗原因:故障資料可能永久存在 → 修正方法:執行絕對過期截止時間。
- 錯誤表現:每個過期讀取都請求來源站 → 失敗原因:過期流量會形成驚群 → 修正方法:按鍵合併重新驗證。
- 錯誤表現:把 TTL 當作緊急失效 → 失敗原因:緊急變更要等到期 → 修正方法:發布 purge 或版本事件並確認完成。
追問與回答
為什麼不只用 stale-if-error?
它只在來源站請求發生錯誤時生效。stale-while-revalidate 用背景成功刷新改善正常延遲。兩者解決的條件不同,需要獨立邊界和指標。
purge 期間驗證器發生變化怎麼辦?
給物件版本化,並讓 purge 事件冪等。看到舊驗證器的重新驗證不能覆蓋更新版本;替換前比較物件版本或提交時間。順序無法確認時,短時間繞過該鍵快取。
CDN 可以快取帶 Vary: Authorization 的驗證回應嗎?
某些系統技術上可以,但風險很高。優先使用 private 或明確的租戶公開表示。如果無法避免共用快取,必須用整合測試和維運控制證明快取鍵、授權獨立性、purge 與跨租戶隔離。