什麼是快取#
負載均衡幫助系統透過增加伺服器來水平擴展,而快取(Cache) 則能讓現有資源發揮更大效用,甚至實現原本不可能達成的產品需求。
快取利用了參考局部性原理(Locality of Reference):最近被請求的資料,很可能會再次被請求。快取廣泛應用於計算的各個層級:
- 硬體
- 作業系統
- 網頁瀏覽器
- 網頁應用程式
快取就像短期記憶體:空間有限,但存取速度通常遠快於原始資料來源,且保存的是最近被存取的項目。快取通常部署在最靠近前端的層級,以便快速回傳資料而不加重下游負擔。
快取的類型#
應用伺服器快取(Application Server Cache)#
將快取直接放在請求層節點上,可在本地儲存回應資料:
- 每次收到請求時,節點會優先回傳本地快取資料
- 若資料不在快取中,再從磁碟查詢
- 快取可同時存放於記憶體(速度最快)和本地磁碟(比網路儲存快)
當請求層擴展為多個節點時,若負載均衡器隨機分配請求,相同請求會被導向不同節點,導致快取命中率下降(Cache Miss 增加)。解決方案包括:全域快取(Global Cache) 和分散式快取(Distributed Cache)。
分散式快取(Distributed Cache)#
在分散式快取中,每個節點持有部分快取資料:
- 通常使用一致性雜湊(Consistent Hashing) 來劃分快取
- 請求節點可快速定位目標資料位於分散式快取的哪個節點
- 每個節點只持有一小部分快取,若本地沒有則向其他節點發送請求,最後才回溯到原始資料來源
- 優點:只需增加節點即可輕鬆擴展快取空間
缺點:當某個節點故障時,該節點上的快取資料將遺失。部分系統會在不同節點上儲存多份副本來應對,但這會增加邏輯複雜度,尤其在新增或移除節點時。即便如此,遺失的快取請求最終仍會從原始資料來源取得,因此並非災難性的問題。
全域快取(Global Cache)#
所有節點共用同一個快取空間,通常是一台比原始資料來源更快、且所有請求層節點都能存取的伺服器或檔案儲存:
- 每個請求節點以與存取本地快取相同的方式查詢全域快取
- 隨著客戶端與請求數量增加,單一快取容易成為效能瓶頸
- 在某些架構下非常有效(如使用專用硬體加速、或快取固定資料集的場景)
全域快取有兩種常見模式:
- 快取主動取回型:當快取未命中時,由快取本身負責從底層儲存取回遺失的資料
- 請求節點取回型:由請求節點自行從底層儲存取回快取中不存在的資料
大多數應用傾向使用第一種模式(快取自行管理淘汰與取回),以避免大量客戶端同時請求相同資料。但在以下情況適合使用第二種模式:
- 快取用於超大檔案,低命中率會導致快取緩衝區被大量未命中請求淹沒
- 快取中的檔案是靜態的、不應被淘汰(例如應用程式對特定資料有低延遲需求,或應用邏輯比快取更了解淘汰策略與熱點分佈)
內容分發網路(Content Distribution Network, CDN)#
CDN 是一種適用於提供大量靜態媒體內容的快取機制:
- 請求先向 CDN 取得靜態媒體資源
- 若 CDN 本地有該內容,直接回傳
- 若沒有,CDN 向後端伺服器查詢,快取後再回傳給使用者
若系統規模尚未大到需要自建 CDN,可先將靜態媒體放在獨立子網域(例如
static.yourservice.com),使用輕量級 HTTP 伺服器如 Nginx 提供服務,未來再透過 DNS 切換至 CDN,實現平滑遷移。
快取失效策略(Cache Invalidation)#
快取雖然強大,但需要維護機制確保快取與資料來源(如資料庫)的一致性。當資料庫中的資料被修改,快取中的對應資料若未失效,將導致應用行為不一致。
以下是三種主要的快取失效策略:
寫入穿透快取(Write-Through Cache)#
- 資料同時寫入快取與資料庫
- 快取資料可快速讀取,且與持久化儲存保持完全一致
- 即使發生當機、斷電或其他系統中斷,也不會遺失資料
- 缺點:每次寫入操作都要執行兩次才能回傳成功,導致寫入延遲較高
寫入繞過快取(Write-Around Cache)#
- 資料直接寫入持久化儲存,繞過快取
- 可減少快取被大量不會被重新讀取的寫入操作淹沒
- 缺點:對最近寫入的資料進行讀取時,會產生 Cache Miss,需從較慢的後端儲存讀取,延遲較高
回寫快取(Write-Back Cache)#
- 資料僅寫入快取,立即向客戶端確認完成
- 寫入持久化儲存的操作在指定間隔或特定條件下才執行
- 優點:寫入密集型應用可享有低延遲、高吞吐量
回寫快取的風險在於:若發生當機或其他異常事件,僅存於快取中的資料可能遺失,因為持久化儲存尚未同步。
快取淘汰策略(Cache Eviction Policies)#
以下是常見的快取淘汰策略:
- 先進先出(FIFO, First In First Out):最先進入快取的資料最先被淘汰,不考慮存取頻率或次數
- 後進先出(LIFO, Last In First Out):最近進入快取的資料最先被淘汰,不考慮存取頻率或次數
- 最近最少使用(LRU, Least Recently Used):淘汰最久未被存取的資料
- 最近最常使用(MRU, Most Recently Used):與 LRU 相反,淘汰最近被存取的資料
- 最不常使用(LFU, Least Frequently Used):統計每筆資料的存取頻率,淘汰使用次數最少的資料
- 隨機替換(RR, Random Replacement):隨機選擇一筆資料進行淘汰