1. 程式人生 > 其它 >redis快取擊穿,穿透,雪崩

redis快取擊穿,穿透,雪崩

redis快取擊穿,穿透,雪崩

redis快取雪崩

快取雪崩是指,有大量的快取在同一時刻過期或者redis宕機,造成大量的請求打入資料庫

解決方案:

redis設定過期時間儘量分散,設定隨機過期時間。

事前:保證高可用,叢集搭建,主從+哨兵,讀寫分離,cluster叢集

事中:本地ehcache快取 + hystrix 或 sentinel 熔斷&限流&降級,避免mysql被打死

事後:redis持久化,快速恢復快取資料,AOF,RDB

redis快取擊穿

快取擊穿是指一個熱點key失效,導致大量的請求打入資料庫。

解決方案:

設定熱點key永不過期

使用本地ehcache快取+hystrix或sentinel熔斷&限流&降級,避免mysql被打死

redis快取穿透

快取穿透是指惡意請求訪問,比如查詢id傳入負數,資料庫和快取都沒有這個資料

問題1:

假設黑客模擬大量請求訪問id為-1的資料,這個資料快取中肯定是沒有的,所以這些請求就打到資料庫上面了

解決方案1:

把空結果寫到快取中去,比如:key:-1 value:null expire:15s

問題2:

如果是-1,-2,-3這樣的請求,上面方法反而會起到適得其反的作用,導致redis記憶體大量消耗

解決方案2:

使用布隆過濾器,布隆過濾器可以返回一個key存在,則這個key可能存在,返回不存在,則一定不存在。

布隆過濾器原理:

布隆過濾器大概是一個數組,或者一個bitmap,一個key請求過來之後,會經過多個hash演算法運算,每個hash演算法不一樣,得到多個hash值,這個時候去記錄陣列對應下標為1;

列如:新增資料的時候,新增id為1的資料,經過多個hash運算,分別得到 1,3,5的結果

則把陣列的結果修改為int[] arr = {0,1,0,1,0,1,0,0,0,0,0,0,0}

id為2的資料來了,hash運算得到3,4,7

則把陣列的結果修改為{0,1,0,1,1,1,0,1,0,0,0,0,0}

查詢的時候,如果請求為1,那對應hash結果為1,3,5,去陣列找到對應下標的結果是否都為1,如果為1,說明這個id存在,可以允許訪問。

如果查詢-1,那hash運算結果為3,4,6,找對應下標,發現6不為1,所以這個id必不存在,這個請求無效。

問題很明顯:

如果布隆過濾器的長度不夠的話,可能會出現{1,1,1,1,1,1,1,1,1,1,1,1,1}的情況,那所有請求都會認為存在了。

無法刪除資料,對一個數據刪除的時候,無法去修改1為0,因為對應的下標可能是其他元素的hash運算結果。

hash演算法的個數需要巧妙設計,以及用哪些演算法。

不過不用擔心用googlet提供的,案例就不多寫了

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>19.0</version>
</dependency>

還可以使用布穀鳥過濾器

布穀鳥過濾器原理:

鳩佔鵲巢的思想,一個一個擠走。

布穀鳥過濾器是在布隆過濾器基礎上的一個改進,他一樣計算出多個hash值,這個時候可以把多個hash值看作一個個巢,比如現在id為1的元素,他有3個巢為1,3,5.那他第一次會去1的巢穴,id為2的元素,如果計算得到1,4,7。他去1的位置,發現id為1的已經佔了這個位置,那他會把id為1的擠走,自己佔領。這個時候id為1的元素被擠走了之後會去找他第二個巢穴,就是3這個位置。如果3位置有其他元素,那這個元素也會被擠走,找他的其他巢穴。

思想設計還可以,落地實現沒有。

快取穿透總結:

我來寫直接用解決方案1,加快取裡面,這個如果是springboot2.x+spring3.1之後,而且引入了redis,那麼加一個註解@Cacheable("menu") ,把結果快取起來。

開啟spring-cache配置,快取結果為null的資料。


spring.cache.redis.cache-null-values=true

切記理論是一回事,落地實現是另一回事,主要還是看公司。

再提一點,可以對惡意請求的ip加入黑名單,那就是Gatway的操作了,這裡不做闡述。