App下載

關(guān)于 緩存穿透/緩存擊穿/緩存雪崩 看這篇文章就夠了

猿友 2020-10-13 16:23:40 瀏覽數(shù) (2958)
反饋

國慶加中秋過去了,大家準備好學習了么?

redis 在項目中用的話,主要就是用作緩存了

既然用作緩存,那就肯定會有 緩存穿透/緩存擊穿/緩存雪崩 的問題

這篇文章就來說說,遇到這種情況時,該如何去處理

緩存穿透

首先咱們搞明白什么是緩存穿透?這三個詞這么像,得把概念搞清楚不是

其實只是從字面意思上來看的話,大概也能知道一點兒,緩存穿透嘛,就是直接穿過了緩存,將請求打到了數(shù)據(jù)庫上面去

一般情況下,去查詢數(shù)據(jù)的話,緩存里面應該都是有的,但是防不住黑客呀,如果黑客請求查詢的是數(shù)據(jù)庫里面根本不存在的數(shù)據(jù),數(shù)據(jù)庫里面都沒有的數(shù)據(jù),緩存里面肯定也不會有了,對吧,那么此時請求就會打到咱們的數(shù)據(jù)庫里面去,這就是緩存穿透

你想啊,黑客想要攻擊的話,怎么可能只請求一次呢,肯定是大量的請求過來,因為是拿數(shù)據(jù)庫里面不存在的 id 來請求的,那么這些請求毫無疑問直接打到了數(shù)據(jù)庫上面去,那咱們的數(shù)據(jù)庫可能就會因為這些大量的請求直接宕掉

如何解決呢?

咱們回到產(chǎn)生這個問題的場景中,為什么大量的請求會打到數(shù)據(jù)庫上面來?因為緩存里面沒有對應的 key 對吧,所以才會越過緩存直接到數(shù)據(jù)庫

那么問題就好解決了嘛,緩存里面沒有對應的 key ?OK ,如果這個 key 數(shù)據(jù)庫里面也沒有,那我就在 redis 里面,存上這個 key ,值是 null ,這樣如果有查詢這個 key 的請求,我直接返回 null 就完事兒了,也就不用打到數(shù)據(jù)庫上面去了

注意一下,要記得設(shè)置它的過期時間,一般三到五分鐘就夠了

但是對方是個黑客呀,可能就用一個 key 去請求么?他可能會在短時間內(nèi)用大量的 key 來發(fā)送請求,那如果一個 key 就在 redis 中存儲一個 null 值的話,那么多 key 是不是就會存儲那么多個 null 值嘞?

這樣的話, redis 里面是不是都是值為 null 的了?

所以有沒有更好的解決辦法呢?

那必須得有!布隆過濾器,你值得嘗試

什么是布隆過濾器呢?就是它能告訴你,某個值一定不存在或者可能存在( emmmm ,也不知道我有沒有說清楚

所以可以將數(shù)據(jù)庫的內(nèi)容緩存一份到布隆過濾器,這樣的話,當大量的請求過來的時候, redis 里面沒有,沒關(guān)系,再去布隆過濾器過濾一下,這樣請求不用打到數(shù)據(jù)庫上面去,就能確定這個 key 數(shù)據(jù)庫中有沒有

這樣不就降低了數(shù)據(jù)庫的壓力么,可真是個天才~

緩存擊穿

緩存擊穿說的是,在高并發(fā)情況下,如果好多個請求都在查詢一個 key ,好巧不巧的是,這個 key 因為某些原因失效了(比如設(shè)置的過期時間到了,緩存服務器宕機了),這樣就會導致那么多的請求都直接打到數(shù)據(jù)庫上面去了

那如果這些請求的數(shù)量足夠大的話,可能直接把數(shù)據(jù)庫就干掉了

知道了造成結(jié)果的原因,那么尋找解決方案也就好辦了

不是因為好多個請求打到了數(shù)據(jù)庫嘛,但是它們請求的都只是一個 key ,所以這里可以使用排斥鎖來實現(xiàn),第一個請求達到請求 key 發(fā)現(xiàn)緩存里面沒有,允許它去數(shù)據(jù)庫查詢,同時加鎖,這樣第二個請求,第三個請求…都會被鎖阻塞到當前,不會再打到數(shù)據(jù)庫,這樣就減少了數(shù)據(jù)庫的并發(fā)壓力

緩存雪崩

緩存雪崩,雪崩雪崩嘛,就比較嚴重,擊穿說的是一個 key 失效的情況,雪崩指的是大規(guī)模的緩存失效情況的發(fā)生,這是有可能發(fā)生的,比如說我的緩存服務器宕機了,那是不是直接就大規(guī)模的緩存失效了;或者說,我當時為了圖省事,好多個 key 設(shè)置的過期時間都是一樣的,然后剛好在緩存都失效的時候,好多請求不同的 key 過來了

解決方案的話,其實就不適合使用加鎖的方式去解決了,因為這是好多請求不同的 key ,它不是一個嘛

而且嘞,咱們是因為好多個 key 設(shè)置的過期時間都是一樣的,所以解決方案就是,咱們不設(shè)置同樣的時間讓緩存失效了,咱們給一個隨機時間,讓緩存隨機失效,這樣的話,大規(guī)模的緩存失效情況就減少很多了

那還要一種情況呢,就是如果我的緩存服務器直接宕機了,這怎么辦?也好弄,來個集群就解決了,這里只是一個解決方案,它的落地實現(xiàn)不是本文重點哈~

再談 布隆過濾器

OK ,你如果看到這里的話,其實這篇文章的內(nèi)容就說完了

但是我感覺布隆過濾器那塊,我沒有說清楚,所以在這里拿出來詳細說一說(我知道你一定又在默默夸阿粉是個暖男了,乖,知道就好了,不要真說出來,我會害羞的

布隆過濾器是一種數(shù)據(jù)結(jié)構(gòu),它是一種概率型的數(shù)據(jù)結(jié)構(gòu),就是它能告訴你“某樣東西一定不存在或者可能存在”

你可能會說,這話剛剛不是說過了嘛,本來就挺拗口的,你咋還說

還不是因為這句話比較重要,我覺得把這句話理解透徹了,那么對布隆過濾器理解的應該也就到位了

來,為了形象生動一些,咱們舉個例子~ 布隆過濾器是一個 bit 向量或者說 bit 數(shù)組,大概長這樣:

布隆過濾器

現(xiàn)在,我們需要把 “AliPay” 這個字段給存儲進去 大概的存儲過程就是:將要映射的值,使用多個不同的哈希函數(shù)生成多個哈希值,然后每個生成的哈希值指向的 bit 置為 1

以給的為例,我們現(xiàn)在將 “AliPay” 這個值,通過三個不同的哈希函數(shù)進行映射,那么大概就是這樣了:

三個不同的哈希函數(shù)進行映射

同樣,現(xiàn)在我要存儲另外一個值 “WechatPay” ,那么可能映射之后就是下面這樣:

WechatPay

細心的你可能就會發(fā)現(xiàn), 4 號位置的值,剛開始不是給 “AliPay” 了么,后來 “WechatPay” 也在那里,這樣的話,值不就給覆蓋掉了嘛

嗯,沒錯,是被覆蓋掉了

接下來,我們查詢 “Ali” 那么查詢之后,布隆過濾器可能會給你 “0,1,2” 的值, 結(jié)果呢 “2” 的位置是 0 ,說明沒有任何值映射到這個位置上來,所以我們就可以判定數(shù)據(jù)庫里面沒有 “Ali” 這個值

那我查詢 “AliPay” 的話,毫無疑問,肯定會返回給我 “1,4,6” ,那我們能說數(shù)據(jù)庫里面一定有 “AliPay” 么?不能,因為 “1,4,6” 的值有可能被其他的值給覆蓋到了,所以我們只能說,數(shù)據(jù)庫里可能存在 “AliPay”

這就是布隆過濾器說的"某個值一定不存在或者可能存在"

乖,你懂了嗎?

文章來源于公眾號:Java極客技術(shù) 作者:鴨血粉絲

以上就是W3Cschool編程獅關(guān)于關(guān)于 緩存穿透/緩存擊穿/緩存雪崩 看這篇文章就夠了的相關(guān)介紹了,希望對大家有所幫助。

0 人點贊