【Redis】緩存穿透和緩存雪崩

緩存穿透 (查不到)

數據庫中沒有, 緩存中自然沒有, 所以就會頻繁的去數據庫中查.

布隆過濾器

布隆過濾器式一種數據結構,對所有可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄,從而避免了對底層存儲系統的查詢壓力.

pravate static BloomFilter<Integer> bloomFilter = BloomFilter.create(FUnnels.integerFunnel(),size,fpp);
//本質是一個集合 內置是bitmaps 利用的是 位圖  0 1  m

利用若干 個HASH 函數 ,先把所有數據添加進去,新的來了 查看 只要有一個爲0 那麼就是一定不存在,若都爲一 ,可能存在,這個時候先去redis 找,找不到再去數據庫。

缺點:維護比較麻煩,而且不能刪除 所以要定期維護

緩存空對象

當存儲層不命中後,將返回的空對象存儲起來,同時設置一個過期時間,之後在訪問這個數據就會從緩存中獲取

緩存擊穿(量太大,緩存過期)

一個數據剛剛好失效,或者緩存中沒有這個數據 這個時候併發訪問.

也就是緩存擊穿是量太大了,一個key非常熱點,大併發集中對這一個點進行訪問,這個key失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫

設置熱點數據永不過期

但是永不過期 會有別的問題

加互斥鎖

分佈式鎖: 使用分佈式鎖,保證對於每個key同時只有一個線程去查詢後端服務,其他線程沒有獲得分佈式鎖的權限,因此只需要等待即可.
這種方式將高併發的壓力轉移到了分佈式鎖,因此對分佈式鎖的考驗很大.

  1. 爲什麼需要分佈式鎖
    如果原本我們的系統分佈在一臺機器上的時候,JVM提供的鎖就能解決併發問題。但是如果我們是使用多臺機器,要同時去Redis裏面去拿同一個Key 這個時候,就會發生併發問題,因爲這個時候JVM的鎖事無法解決這個問題。
  2. 基於Resid的分佈式鎖
  • 最簡單的方法是使用setnx 命令,Key 是鎖的唯一標識(加鎖

    • setnx key value :是去redis嘗試set 如果裏面已經有key 那麼就設置失敗返回0

    ps:這裏其實就是利用的redis的原子性 實現了CAS的效果。

  • 有加鎖就得有解鎖。當得到鎖的線程執行完任務,需要釋放鎖,以便其他線程可以進入。釋放鎖的最簡單方式是執行 del 指令(解鎖

    • del key:刪去Key 達到解鎖的效果
  1. 鎖超時
    因爲如果宕機 不給鎖設置超時,那麼就會死鎖 ,所以在 setnx的時候需要設置超時時間。expire key times
  2. 問題!
  • 第一點: 在加鎖和鎖超時的時候 不是原子操作
    • 解決方案:可以利用lua ,set 可以添加可選參數
  • del 誤刪:如果某個業務邏輯的時間超過了超時時間,這個時候如果key 已經被刪除了就會有第二個邏輯進來操作 從而沒有達到鎖的效果。
    • 解決方案:使用守護線程 一直去給我們的key 加上超時時間,這樣會讓鎖不被釋放。
      • 守護線程:開闢一個線程 如果主線程掛了或者結束 那麼守護線程也會結束。

緩存雪崩

在某一個時間段,緩存集中過期失效,或者Redis宕機.

redis高可用

既然redis有可能掛,就多增設幾臺redis
即高可用高效集羣

限流降級

在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量.

數據預熱

在正式部署前,先把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數據就會加載到緩存中. 在即將發生大併發訪問前手動觸發加載緩存不同的key,設置不同的過期時間,讓緩存失效的時間點儘量均勻.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章