緩存穿透、緩存併發和緩存雪崩是常見的因爲併發量大而致使的緩存問題。這裏記錄下其產生緣由和解決方案。數據庫
緩存穿透是由惡意攻擊或無心形成的;緩存併發是由設計不足形成的;緩存雪崩是由緩存同時失效形成的。後端
概念:緩存
緩存穿透指的是使用不存在的 key 進行大量的高併發查詢,這致使緩存沒法命中,每次請求都要穿透到後端數據庫系統進行查詢,使數據庫壓力過大,甚至使數據庫服務被壓死。服務器
解決方案:併發
一、咱們一般將空值緩存起來,再次接收到一樣的查詢請求時,若命中緩存而且值爲空,就會直接返回,不會穿透的數據庫,避免緩存穿透。異步
二、固然,有時惡意襲擊者能夠猜到咱們使用了這種方案,每次都會使用不一樣的參數來查詢,這就須要咱們對輸入的參數進行過濾,例如,若是咱們使用 ID 進行查詢,則能夠對 ID 的格式進行分析,若是不符合產生 ID 的規則,就直接拒絕,或者在 ID 上放入時間信息,根據時間信息判斷 ID 是否合法 ,或者是不是咱們曾經生成的 ID,這樣能夠攔截必定的無效請求。分佈式
概念:高併發
緩存併發的問題一般發生在高併發的場景下,當一個緩存 key 過時時,由於訪問這個緩存 key 的請求量較大,多個請求同時發現緩存過時,所以多個請求會同時訪問數據庫來查詢最新的數據,而且回寫緩存,這樣會形成應用和數據庫的負載增長,性能下降,因爲併發較高,甚至會致使數據庫被壓死。性能
解決方案:線程
一、分佈式鎖
使用分佈式鎖,保證對於每一個 key 同時只有一個線程去查詢後端服務,其餘線程沒有得到分佈式鎖的權限,所以只須要等待便可。這種方式將高併發的壓力轉移到了分佈式鎖,所以對分佈式鎖的考驗很大。
二、本地鎖
與分佈式鎖相似,咱們經過本地鎖的方式來限制只有一個線程去數據庫查詢數據,而其餘線程只需等待,等前面的線程查詢到數據後再訪問緩存。可是,這種方法只能限制一個服務節點只有一個線程去數據庫中查詢,若是一個服務有多個節點,則還會有多個數據庫查詢操做,也就是說在節點數量較多的狀況下並無徹底解決緩存併發的問題。
三、軟過時
軟過時是指對緩存中的數據設置失效時間,就是不使用緩存服務器提供的過時時間,而是業務層在數據中存儲過時時間信息,由業務程序判斷是否過時並更新,在發現了數據即將過時時,將緩存的時效延長,程序能夠派遣一個線程去數據庫中獲取最新的數據,其餘線程這時看到延長了的過時時間,就會繼續使用舊數據,等派遣的線程獲取最新數據後再更新緩存。也能夠經過異步更新服務來更新設置軟過時的緩存,這樣應用層就不用關心緩存併發的問題了。
概念:
緩存雪崩指緩存服務器重啓或者大量緩存集中在某一個時間段內失效,給後端數據庫形成瞬間的負載升高的壓力,甚至壓垮數據庫的狀況。
解決方案:
一般的解決辦法是對不一樣的數據使用不一樣的失效時間,甚至對相同的數據、不一樣的請求使用不一樣的失效時間。例如,咱們要緩存 user 數據,會對每一個用戶的數據設置不一樣的緩存過時時間,能夠定義一個基礎時間,假設 10 秒,而後加上一個兩秒之內的隨機數,過時時間爲 10 ~ 12 秒,就會避免緩存雪崩。