前言
-
昨天有讀者朋友留言,想要陳某寫一篇防止緩存穿透的文章,今天特地寫了一篇。
-
文章目錄以下:
-
什麼是緩存穿透?
解決方案
緩存空值
Object nullValue = new Object();
try {
Object valueFromDB = getFromDB(uid); //從數據庫中查詢數據
if (valueFromDB == null) {
cache.set(uid, nullValue, 10); //若是從數據庫中查詢到空值,就把空值寫入緩存,設置較短的超時時間
} else {
cache.set(uid, valueFromDB, 1000);
}
} catch(Exception e) {
// 出現異常也要寫入緩存
cache.set(uid, nullValue, 10);
}
複製代碼
-
經過僞代碼能夠很清楚的瞭解了緩存空值的流程,可是須要注意如下問題:
布隆過濾器
-
1970 年布隆提出了一種布隆過濾器的算法,用來判斷一個元素是否在一個集合中。這種算法由一個二進制數組和一個 Hash 算法組成。
-
-
解決緩存穿透的大體思想:
在訪問緩存層和存儲層以前,能夠經過定時任務或者系統任務來初始化布隆過濾器,將存在的 key 用布隆過濾器提早保存起來,作第一層的攔截。例如:一個推薦系統有 4 億個用戶 id, 每一個小時算法工程師會根據每一個用戶以前歷史行爲計算出推薦數據放到存儲層中, 可是最新的用戶因爲沒有歷史行爲, 就會發生緩存穿透的行爲, 爲此能夠將全部推薦數據的用戶作成布隆過濾器。 若是布隆過濾器認爲該用戶 id 不存在, 那麼就不會訪問存儲層, 在必定程度保護了存儲層。此時的結構以下圖:
-
固然布隆過濾器的
假陽性的存在致使了誤判率,可是咱們能夠儘可能的下降誤判率,一個解決方案就是:使用多個 Hash 算法爲元素計算出多個 Hash 值,只有全部 Hash 值對應的數組中的值都爲 1 時,纔會認爲這個元素在集合中。
-
這種方法適用於
數據命中不高
、
數據相對固定
、
實時性低
(一般是
數據 集較大
)的應用場景,代碼維護較爲複雜,可是緩存空間佔用少。爲何呢?由於布隆過濾器不支持刪除元素,一旦數據變化,並不能及時的更新布隆過濾器。
兩種方案對比
方案 |
適用場景 |
維護成本 |
緩存對象 |
1. 數據命中不高 2. 數據頻繁變化,實時性高 |
代碼維護點單、須要過多的緩存空間,數據一致性須要本身實現 |
布隆過濾器 |
1. 數據命中不高 2.數據相對固定,實時性低 |
代碼維護複雜、緩存空間佔用少 |
總結