[Day 28] Caching (一)

erichung0404
2024-08-28 18:33:28

前面我們介紹了分散式系統中對於 可用性 和 一致性 的抉擇
也簡單比較了各個 Database 的設計傾向, 並透過 Replication, Sharding, Consensus 等方式分攤請求以改善效能

今天繼續介紹另一個常見的改善 Database 效能的方式: Caching (快取)

(題外話: Reference 那篇其實已經寫蠻清楚了, 這篇僅用不同角度說明)

Database Caching

由於透過 Database 存取資料時是從硬碟上讀取, 比較耗時間 (請見 Day 2), 雖然我們能透過 Indexing 等方式改善, 但由於這屬於 Database 各自的實作, 我們不討論該細節

既然從硬碟的存取速度很慢, 那我們是否能從記憶體存取資料呢? (速度可以差到 1000 多倍)
所以我們可以將資料存入記憶體中, 讓其他服務能直接從記憶體存取資料, 就能大大改善效能

然而, 若我們將資料存到記憶體中, 就有了 "兩份" 資料, 會有一致性的問題

看過了前面幾篇後, 我們對於如何達成一致性有一定的了解了, 不過相較於前篇提到的 Replica
針對 Caching 的同步策略不太一樣, 主要是因為 Caching 本身的特性

儲存時間: 資料是暫時的, 當 Caching 的節點重啟, 資料就會消失

儲存空間: 由於記憶體的空間相較於硬碟小非常多, 我們不可能也沒有必要將 "所有" 資料同步到 Caching 節點, 可以快取一些 "比較耗時" 的操作就好

常見的模式有

Cache aside

Write back

Write through

Read through

Cache aside

服務 直接將資料寫到 Database 節點, 並從 Caching 節點讀取, 若不存在則從 Database 節點讀取並存到 Caching 節點

所以 服務 需要協調兩者的資料

缺點是第一次一定會 cache miss, 一種解法是先預熱 (Warm Up), 在上線前就先把常用的資料放到 Caching 節點

Write through

服務 透過 Caching 節點存取資料, 不會和 Database 節點互動

缺點是 服務 要等到 Caching 節點將資料寫入 Database 節點, Write-heavy 的情況下很可能有效能瓶頸, 並且不好維護一致性

Write back

服務 透過 Caching 節點存取資料, 不會和 Database 節點互動

和 Write through 的差別是, Caching 節點不會立刻將資料寫入 Database 節點, 而是先存在 Caching 節點再定時批次寫回 Database 節點 (有種 Caching 節點變成 Master 節點的感覺)

缺點是若 Caching 節點發生分區錯誤, 則資料就消失了, 一種解法是 Caching 節點也用分散式架構處理, 避免 SPOF

Read through

服務 直接將資料寫到 Database 節點, 並從 Caching 節點讀取

服務在讀取時不會直接從 Database 節點讀取

缺點也是會有 cache miss

Bloom Filter

由於記憶體的空間有限, 並且我們做最多次的操作就是 "檢查資料是否存在 Caching 節點中"
所以我們可以透過 Bloom Filter 改善檢查的效能, 並且節省記憶體空間, 代價是要承受一些 False Positive 的例外 (Cache 中沒有資料卻回報有)

Reference

淺談各種資料庫cache策略: cache asideread throughwrite throughwrite back

wiki - Bloom filter