Redis—緩存雪崩、緩存擊穿、緩存穿透

1、緩存雪崩

不少時候,Redis中的緩存是要設置過時時間的,假如Redis中的數據,過時時間都設置成同樣的,那麼到了時間以後,所有緩存過時失效,下一秒全部的請求都會訪問數據庫,那麼數據庫可能由於訪問量過大致使「崩潰」,這就是緩存雪崩。html

若是緩存集中在一段時間內失效,發生大量的緩存穿透,全部的查詢都落在數據庫上,形成了緩存雪崩。redis

這個沒有完美解決辦法,但能夠分析用戶行爲,儘可能讓失效時間點均勻分佈。大多數系統設計者考慮用加鎖或者隊列的方式保證緩存的單線程(進程)寫,從而避免失效時大量的併發請求落到底層存儲系統上。算法

應對方法:數據庫

一、緩存永遠不過時:最暴力的解決辦法,緩存不設置自動過時時間,只要緩存不崩,數據庫就不會崩。緩存

二、使用加鎖或者隊列的方式保證來保證不會有大量的線程對數據庫一次性進行讀寫,從而避免失效時大量的併發請求落到底層存儲系統上。併發

加鎖排隊. 限流-- 限流算法. 1.計數 2.滑動窗口 3.  令牌桶Token Bucket 4.漏桶 leaky bucket [1]。框架

在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢數據和寫緩存,其餘線程等待。異步

三、作二級緩存,或者雙緩存策略。spa

A爲原始緩存,B爲拷貝緩存。A失效時,能夠訪問B,緩存A的失效時間爲20分鐘,緩存B不設置失效時間。本身作緩存預熱操做。細分如下幾個小點:線程

  • 從緩存A讀數據庫,有則直接返回。
  • 若緩存A沒有數據,直接從B讀數據,直接返回,而且異步啓動一個更新線程。
  • 更新線程同時更新緩存A和緩存B。

四、給緩存的失效時間,加上一個隨機值,避免集體失效。讓緩存過時時間不那麼一致,好比一批緩存數據24小時後過時,那麼就在這個基礎上,每條緩存的過時時間先後隨機1-6000秒(1-10分鐘)。設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻。

2、緩存擊穿

緩存擊穿跟緩存雪崩有點像,可是又有一點不同,緩存雪崩是由於大面積的緩存失效,打崩了DB,而緩存擊穿不一樣的是緩存擊穿是指一個Key很是熱點,在不停的扛着大併發,大併發集中對這一個點進行訪問,當這個Key在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個無缺無損的桶上鑿開了一個洞。

應對方法:

一、設置熱點數據永遠不過時。或者加上互斥鎖就能搞定了。

https://www.lizenghai.com/archives/27853.html

https://mp.weixin.qq.com/s?__biz=MzUxNDA1NDI3OA==&mid=2247484581&idx=2&sn=54f2306012619e3dbe36c4fcf9493039&chksm=f94a854cce3d0c5a8be0825de18d381b388d247a7a2145759c3818cfcfa28a364bf8b8b38383&mpshare=1&scene=23&srcid=0627JwWmdlo4tdChETfgpSBL#rd

3、緩存穿透

不少項目在使用Redis或其餘緩存框架的時候,都是先查詢緩存,查詢不到的話再查詢數據庫,查到以後再放到緩存(內存)中;若是一個key值自己就不存在,那麼每一次都會查詢數據庫,也就是常說的【緩存穿透】。簡單理解就是先去緩存中找不到,再去數據庫查詢,在數據庫中也找不到,就發生了緩存穿透。

key對應的數據在數據源並不存在,每次針對此key的請求從緩存獲取不到,請求都會到數據源,從而可能壓垮數據源。好比用一個不存在的用戶id獲取用戶信息,不論緩存仍是數據庫都沒有,若黑客利用此漏洞進行攻擊可能壓垮數據庫。

緩存穿透是指查詢一個必定不存在的數據,因爲緩存是不命中時須要從數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,形成緩存穿透。數據在redis不存在,數據庫也不存在,返回空,通常來講空值是不會寫入redis的,若是反覆請求同一條數據,那麼則會發生【緩存穿透】。

應對方法:

一、緩存空對象

若是在Redis中查詢不到,而且查詢數據庫也沒有結果,那麼就將這個key設置一個空值(value=空),同時寫入到Redis中,並設置一個超時過時時間,例如五分鐘,那麼五分鐘之內對這個key的全部查詢就能夠攔截下來,就不會訪問數據庫了。若是數據庫有key對應的數據了,那麼五分鐘後Redis中的緩存過時,會訪問數據庫並加載緩存;可是若是被惡意攻擊,每次請求的key都不相同且在數據庫中也是不存在的,那麼依然會發生緩存穿透,會穿透到數據庫。

 若是一個數據庫查詢返回的數據爲空,咱們仍然把這個空結果進行緩存,但它的過時時間會很短,最長不超過五分鐘。緩存空對象會有兩個問題:

  • 空值作了緩存,意味着緩存層中存了更多的鍵,須要更多的內存空間 ( 若是是攻擊,問題更嚴重 ),比較有效的方法是針對這類數據設置一個較短的過時時間,讓其自動剔除。
  • 緩存層和存儲層的數據會有一段時間窗口的不一致,可能會對業務有必定影響。例如過時時間設置爲 5分鐘,若是此時存儲層添加了這個數據,那此段時間就會出現緩存層和存儲層數據的不一致,此時能夠利用消息系統或者其餘方式清除掉緩存層中的空對象。

二、布隆過濾器

將可能存在的數據Hash到一個足夠大的bitmap上,它能夠告訴你 「某個key必定不存在或者可能存在」,一個必定不存在的數據會被bitmap攔截。

4、緩存併發

大多數時候,咱們的程序訪問Redis都不多是單線程,那麼當多個Client併發對Redis進行set key操做的時候,可能會產生一些問題;其實Redis自己是單線程的,這種時候會按照前後順序進行操做;或者把操做放在隊列中,按順序執行;

但好比這種狀況:

1.token過時,有兩個線程都去從新獲取token;

2.線程1獲取到token1;

3.線程2獲取到token2,此時token1過時;

4.線程1把token1放到Redis,再拿着token1去調用服務,發現過時了,繼續去請求token3,此時token2過時;

5.線程2把token2放到Redis,再拿着token2去調用服務,發現過時了,繼續去請求token4,此時token3過時;

6.... ...

這就須要咱們在更新緩存的時候,作一些控制了。

相關文章
相關標籤/搜索