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


一、緩存雪崩

很多時候,Redis中的緩存是要設置過期時間的,假如Redis中的數據,過期時間都設置成一樣的,那么到了時間之后,全部緩存過期失效,下一秒所有的請求都會訪問數據庫,那么數據庫可能因為訪問量過大導致“崩潰”,這就是緩存雪崩。

如果緩存集中在一段時間內失效,發生大量的緩存穿透,所有的查詢都落在數據庫上,造成了緩存雪崩。

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

應對方法:

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

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

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

在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。

3、做二級緩存,或者雙緩存策略。

A為原始緩存,B為拷貝緩存。A失效時,可以訪問B,緩存A的失效時間為20分鍾,緩存B不設置失效時間。自己做緩存預熱操作。細分以下幾個小點:

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

4、給緩存的失效時間,加上一個隨機值,避免集體失效。讓緩存過期時間不那么一致,比如一批緩存數據24小時后過期,那么就在這個基礎上,每條緩存的過期時間前后隨機1-6000秒(1-10分鍾)。設置不同的過期時間,讓緩存失效的時間點盡量均勻。

二、緩存擊穿

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

應對方法:

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

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

三、緩存穿透

很多項目在使用Redis或其他緩存框架的時候,都是先查詢緩存,查詢不到的話再查詢數據庫,查到之后再放到緩存(內存)中;如果一個key值本身就不存在,那么每一次都會查詢數據庫,也就是常說的【緩存穿透】。簡單理解就是先去緩存中找不到,再去數據庫查詢,在數據庫中也找不到,就發生了緩存穿透。

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

緩存穿透是指查詢一個一定不存在的數據,由於緩存是不命中時需要從數據庫查詢,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,造成緩存穿透。數據在redis不存在,數據庫也不存在,返回空,一般來說空值是不會寫入redis的,如果反復請求同一條數據,那么則會發生【緩存穿透】。

應對方法:

1、緩存空對象

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

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

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

2、布隆過濾器

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

四、緩存並發

大多數時候,我們的程序訪問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.... ...

這就需要我們在更新緩存的時候,做一些控制了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM