首頁  >  文章  >  Java  >  Java快取中的雪崩與擊穿問題及解決方法

Java快取中的雪崩與擊穿問題及解決方法

PHPz
PHPz轉載
2023-05-08 12:43:081827瀏覽

快取雪崩

快取雪崩指的是Redis當中的大量快取在同一時間全部失效,而假如恰巧這段時間同時又有大量請求被發起,那麼就會造成請求直接存取到資料庫,可能會把資料庫沖垮。

快取雪崩一般形容的是快取中沒有而資料庫中有的數據,而因為時間到期導致請求直達資料庫。

解決方案

解決快取雪崩的方法有很多:

  • 1、加鎖,保證單執行緒存取快取。這樣就不會有許多請求同時存取資料庫。

  • 2、失效時間不要設定成一樣。典型的就是初始化預熱資料的時候,將資料存入快取時可以採用隨機時間來確保不會咋同一時間有大量快取失效。

  • 3、記憶體允許的情況下,可以將快取設定為永不失效。

快取擊穿

快取擊穿和快取雪崩很類似,差別就是快取擊穿一般指的是單一快取失效,而同一時間又有很大的並發請求需要存取這個key,從而造成了資料庫的壓力。

解決方案

解決快取擊穿的方法和解決快取雪崩的方法很類似:

  • 1、加鎖,保證單執行緒訪問快取.這樣第一個請求到達資料庫後就會重新寫入緩存,後續的請求就可以直接讀取快取。

  • 2、記憶體允許的情況下,可以將快取設定為永不失效。

快取穿透

快取穿透和上面兩個現象的本質差異就是這時候存取的資料其在資料庫中也不存在,那麼既然資料庫不存在,所以快取裡面肯定也不會存在,這樣如果並發過大就會造成資料來源不斷的到達資料庫,對資料庫造成極大壓力。

解決方案

對於快取穿透問題,加鎖並不能起到很好地效果,因為本身key就是不存在,所以即使控制了線程的訪問數,但是請求還是會源源不絕的到達資料庫。

解決快取穿透問題一般可以採用以下方案配合使用:

  • 1、介面層進行校驗,發現非法的key直接回傳。例如資料庫中採用的是自增id,那麼如果來了一個非整數的id或負數id可以直接回,或者說如果採用的是32位uuid,那麼發現id長度不等於32位也可以直接回傳。

  • 2、將不存在的資料也進行緩存,可以直接緩存一個空或其他約定好的無效value。採用此方案最好將key設定一個短期失效時間,否則大量不存在的key被儲存到Redis中,也會佔用大量記憶體。

布隆過濾器(Bloom Filter)

針對上面快取穿透的解決方案,我們思考一下:假如一個key可以繞過第1種方法的校驗,而此時有大量的不存在key被訪問(如1億個或10億個),那麼這時候全部存儲到緩存,會佔用非常大的空間,會浪費大量服務器內存,導致內存不足。

那麼有沒有更好的解決方案呢?這就是我們接下來要介紹的布隆過濾器,布隆過濾器就可以最大程度的解決key值過多的這個問題。

什麼是布隆過濾器

可能大部分人都知道有這麼一個面試問題:如何在10億的海量的無序的數據中快速判斷一個元素是否存在?

要解決這個問題就需要用到布隆過濾器,否則大部分伺服器的記憶體是無法儲存這麼大的數量級的資料的。

布隆過濾器(Bloom Filter)是由布隆在1970年提出的。它實際上是一個很長的二進位向量(位圖)和一系列隨機映射函數(雜湊函數)。

布隆過濾器可以用來檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都比一般的演算法要好的多,缺點是有一定的誤識別率而且刪除困難。

位圖(Bitmap)

Redis當中有一種資料結構就是位圖,布隆過濾器其中重要的實現就是位圖的實現,也就是位數組,並且在這個數組中每一個位置只有0和1兩種狀態,每個位置只佔用1個位元組,其中0表示沒有元素存在,1表示有元素存在。如下圖所示就是一個簡單的布隆過濾器範例(一個key值經過哈希運算和位元運算就可以得出應該落在哪個位置):

Java快取中的雪崩與擊穿問題及解決方法

哈希碰撞

上面我們發現,lonely和wolf落在了同一個位置,這種不同的key值經過哈希運算後得到相同值的現象就稱之為哈希碰撞。發生哈希碰撞之後再經過位元運算,那麼最後一定會落在同一個位置。

如果發生過多的哈希碰撞,就會影響到判斷的準確性,所以為了減少哈希碰撞,我們一般會綜合考慮以下2個因素:

  • 1、增大位圖數組的大小(點陣圖數組越大,佔用的記憶體越大)。

  • 2、增加雜湊函數的次數(同一個key值經過1個函數相等了,那麼經過2個或更多個雜湊函數的計算,都得到相等結果的機率就自然會降低了)。

上面兩個方法我們需要綜合考慮:例如增加位數組,那麼就需要消耗更多的空間,而經過越多的雜湊計算也會消耗cpu影響到最終的計算時間,所以位數組到底多大,雜湊函數次數又到底需要計算多少次合適需要具體情況具體分析。

布隆過濾器的2大特點

下面這個就是一個經過了2次哈希函數得到的布隆過濾器,根據下圖我們很容易看到,假如我們的Redis根本不存在,但是Redis經過2次雜湊函數之後得到的兩個位置已經是1了(一個是wolf透過f2得到,一個是Nosql透過f1得到)。

Java快取中的雪崩與擊穿問題及解決方法

所以透過上面的現象,我們從布隆過濾器的角度可以得到布隆過濾器主要有2大特點:

  • #1、如果布林過濾器判斷一個元素存在,那麼這個元素可能存在。

  • 2、如果布林過濾器判斷一個元素不存在,那麼這個元素一定不存在。

而從元素的角度也可以得到2大特點:

  • 1、如果元素實際存在,那麼布隆過濾器一定會判斷存在。

  • 2、如果元素不存在,那麼布隆過濾器可能會判斷存在。

PS:需要注意的是,如果經過N次雜湊函數,則需要得到的N個位置都是1才能判定存在,只要有一個是0,就可以判定為元素不存在布隆過濾器中。

fpp

因為在布隆過濾器中總是會存在誤判率,因為雜湊碰撞是不可能百分之百避免的。布隆過濾器對此誤判率稱為假陽性機率,即:False Positive Probability,簡稱fpp。

在實踐中使用布隆過濾器時可以自己定義一個fpp,然後就可以根據布隆過濾器的理論計算出需要多少個雜湊函數和多大的位數組空間。要注意的是這個fpp不能定義為100%,因為無法百分保證不發生哈希碰撞。

以上是Java快取中的雪崩與擊穿問題及解決方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除