[Redis]快取穿透/快取擊穿/快取雪崩

Duancf發表於2024-08-17

快取穿透

使用者訪問一些不存在的資料,redis沒有,於是去mysql查詢也沒有,這樣就發生了兩次無效的查詢。

快取穿透是指客戶端請求的資料在快取中和資料庫中都不存在,快取永遠不會生效。這樣,每次針對此 key 的請求從快取獲取不到,請求都會壓到資料來源,從而可能壓垮資料來源。比如用一個不存在的使用者 id 獲取使用者資訊,不論快取還是資料庫都沒有,若駭客利用此漏洞進行攻擊可能壓垮資料庫。

解決方案

布隆過濾器

設定布隆過濾器,布隆過濾器實際上就是一個陣列加上幾個雜湊函式。

如果布隆過濾器告訴我們這個資料不存在那就一定不存在,如果他說存在,那也不一定存在。

原理是,使用多個雜湊函式,把一個key值使用多個雜湊函式進行運算,把相應的位置設定為1。
當我們想要請求某個資料的時候,先用這幾個雜湊函式對映到陣列的幾個位置,如果這幾個位置都是1,那就是存在,否則就不存在。

使用多個雜湊函式是為了避免雜湊衝突,從而減少誤判,雜湊衝突會導致,例如A和B使用同一個雜湊函式產生了雜湊衝突,先把A放進快取,然後我們想要獲取B的時候發現相應位置上的標誌位已經被設定了,那我們以為這個資料是存在的,但實際上這個位置是因為雜湊衝突被另一個資料標誌的,增加雜湊函式可以降低雜湊衝突的機率。

  • 對空值進行快取:即使一個查詢返回的資料為空,仍然把這個空結果(null)進行快取,同時還可以對空結果設定較短的過期時間。這種方法實現簡單,維護方便,但是會額外的記憶體消耗。
  • 採用布隆過濾器:(布隆過濾器(Bloom Filter)是 1970 年由布隆提出的。它實際上是一個很長的二進位制向量(點陣圖)和一系列隨機對映函式(雜湊函式)。布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的演算法,缺點是有一定的誤識別率和刪除困難。
  • 進行實時監控:當發現 Redis 的命中率開始急速降低,需要排查訪問物件和訪問的資料,和運維人員配合,可以設定黑名單限制服務
  • 增強 id 的複雜度,避免被猜測 id 規律
  • 做好資料的基礎格式校驗
  • 加強使用者許可權校驗

快取擊穿

redis刪掉了熱點資料,導致大量請求傳送到mysql。

解決方案

互斥鎖

這種情況下,執行緒的邏輯應該是這樣的,

首先去查快取,

  • 如果快取裡沒有,嘗試去設定一個分散式鎖(這裡實際上就是在redis中set一個鍵值對set ex nx),誰先設定成功了誰就獲得了這個鎖,
    • 獲得🔒的執行緒去查詢資料庫,
      • 如果查到了把資料寫回快取,
      • 如果發現沒有,也要把資料寫回快取,只是要把值設定成Null,讓其他執行緒知道資料庫裡沒有這個資料,
    • 其他被互斥鎖阻塞的執行緒的操作應該是這樣的,
    • 嘗試獲取鎖,但是這個操作是有過期時間的,超過一定時間還沒有獲取到鎖,就再次去查詢快取,看看快取裡是不是有資料了,有資料也分兩種情況,一種是真的資料,一種是值為null的資料,不管哪種,執行緒都會結束迴圈,但是如果查詢快取的時候發現還是沒有這個資料,那就繼續嘗試獲取鎖
  • 如果快取裡有,直接返回

邏輯過期,

熱點資料永不過期

在快取失效的時候,透過加鎖的方式只允許一個請求重新載入快取資料,其他請求等待快取載入完成。這樣可以避免大量的請求同時訪問資料庫。

快取雪崩

redis同時刪掉了一批熱點資料,導致大量請求傳送到mysql。

快取雪崩是指在同一時段大量的快取 key 同時失效,或者 Redis 服務當機,導致大量請求到達資料庫,帶來巨大壓力。

解決方案

失效時間設定隨機

設定叢集

在快取失效的時候,透過加鎖的方式只允許一個請求重新載入快取資料,其他請求等待快取載入完成。這樣可以避免大量的請求同時訪問資料庫。

  • 給不同的 Key 的 TTL 新增隨機值
  • 利用 Redis 叢集提高服務的可用性
  • 給快取業務新增降級限流策略
  • 給業務新增多級快取

相關文章