大廠面試Redis:緩存雪崩、緩存穿透、緩存擊穿
本文轉載自微信公眾號「大魚仙人」,作者大魚。轉載本文請聯系大魚仙人公眾號。
眼光不錯,小伙子,看到這篇文章了就血賺,這篇文章絕對讓你學到開心,這是面試的殺器,其實Redis這個東西吧,我個人認為,真的真的很強大,但是呢,又感覺被吹得有點過頭了
不過人家也確實有這個資本,人家性能強大,使用操作也很簡單,有提供了各種持久化手段來解決斷電丟失的問題,而且人家讀寫速度都是大幾萬每秒,甚至十幾萬的速度,性能強大而且使用簡單,所以絕大多數的公司都會使用Redis
于是乎,Redis的面試的優先級也是被大大的提高了,而Redis中的經典的緩存的各種問題,也是成為了程序員的必備技能之一
緩存雪崩、緩存穿透和緩存擊穿都是屬于比較典型的問題,當然這篇文章就是為了給大家解釋清楚這三者到底是怎么回事,還有一般情況下如何來解決相應的問題,當然這篇也沒有什么很特殊的厲害的法子,相應的法子估計百度也是一大堆
不過呢,相見既緣分,你看到這篇文章了,我當然要給親愛的大家準備一篇最齊全的解決法子咯,幫助大家真正的了解并學會解決這些問題
緩存雪崩
不過呢,相見既緣分,你看到這篇文章了,我當然要給親愛的大家準備一篇最齊全的解決法子咯,幫助大家真正的了解并學會解決這些問題
雪崩,這個詞聽著就很糟糕,可能很多人已經猜到了個大概了,這指的就是大面積的緩存集體失效
舉個典型的例子,在寫入本文的時候,比如馬上到618的時候,就會很快迎來了一波大促銷,大搶購,就是因為訪問量特別的高,所以要把這些商品都放在緩存中提高效率,假設這一個頁面的數據都緩存了一個小時,那么到了凌晨一點鐘的時候,這些商品的緩存就都會過期了,而對這批商品的訪問,就都落在了DB上,這樣DB就會很容易崩潰
當一點的時候每秒八千個請求,本來緩存可以挺住五千每秒的請求,但是當緩存突然失效的時候,這每秒八千的請求直接全都打在DB上,數據庫直接就扛不住了,沒準直接就掛了,此時如果沒用什么特別的方案來處理這個故障,DBA也容易崩潰,重啟數據庫,但是會立即被下面的流量打崩
這就是我個人理解的緩存雪崩
同一時間的緩存大面試失效,對于線上的情況來說,應該會是一個災難,如果你這么做了,恭喜你,埋下了一個大雷,你想想啊,如果DB直接崩了,那意味著用戶可能要開始***了,這個時候用戶都是熬夜熬了很久等著購買自己心愛的產品呢,結果你軟件崩了,啥也買不了了
什么,連我辛苦好幾天搶的券都不能用了,什么破軟件,卸載,再也不用了,如果真出現這樣的場景,收拾東西吧
說的不錯,這是個大問題,那一般這種情況該如何處理呢,你都是如何應對的
其實處理這個也很簡單了,在批量的往Redis中放置數據的時候,把每個key的失效時間都加個相應的隨機值即可
這樣就可以避免大面積的緩存數據在同一時間失效這個問題,公司一般使用Redis都是集群部署的,這樣將熱點數據均勻分布在不同的Redis庫中也可以避免全部失效的問題,失效時間設為隨機有時候也是一種不錯的策略
或者設置熱點數據永遠不過期,有更新操作就直接更新緩存就好了,看到數據A的緩存過期了,再重新緩存下,數據B的緩存過期了,再重新緩存下B,這樣也可以刷下緩存就好了
緩存穿透和緩存擊穿
我們先來說下緩存穿透,緩存穿透指的是緩存和數據庫都沒有的數據,然而用戶卻不斷的發起請求,這樣的很可能是就是屬于惡意請求
舉個例子,我們數據庫的ID都是自增上去的,如果發起者的ID為-1的情況,或者ID不存在的特別大的情況,這時候的用戶很可能是攻擊者,造成數據庫的攻擊壓力會變得很大,嚴重的可能會導致直接打崩DB
其實這種情況,程序員一般會對這種惡意情況進行過濾,但是萬一有漏洞呢,萬一有程序員忘記了對參數進行校驗,這種情況如果一直用小于0的參數去請求你,每次都能繞開Redis直接打到DB,數據庫查不到,每次都這樣,并發高點可能就會容易搞崩,一些小的單機系統,基本上用postman可能就能打崩
至于緩存擊穿嗎,這個和緩存雪崩有點像,但是肯定也是有不一樣的地方,緩存雪崩是因為大面積的緩存失效,打崩了DB,而緩存擊穿不同的是緩存擊穿指的是一個Key非常熱點,比如之前的某爽這種事情,占用公共資源的眼球,人們都去噴,此時這個Key就是一個大熱點,在不停的扛著大并發,大并發集中的對這一個點進行訪問,當這個key在失效的那一瞬間,也就是某爽的這個key突然失效了,持續的大并發就會直接穿破緩存,直接將請求打到DB,就像是在一個完好無損的桶上鑿開了一個洞
那該如何解決呢,緩存穿透和擊穿這兩種情況
緩存穿透嗎,這個是程序員必須要做的防備之一,接口層的校驗,比如參數的校驗、用戶的鑒權行為這種,對于那些不合法的請求直接return或者報錯就好了
我們在開發的時候,不僅要把用戶的行為各種猜測,我們還要做的是提防各種惡意請求,我們要對程序的各個接口有一顆不信任的心,這個不信任指的是對于參數的各種情況、對于用戶行為的多方面考慮,因為你不能確定來的請求一定是正常的,不能保證調用方一定是正常的調用方,所以一定要對那些非正常的調用方進行一定的校驗和處理
緩存穿透這種需要在代碼中根據業務的實際情況來做出相應的控制,對不符合條件的請求做出相應的過濾,這應該屬于做基本的要求之一,如果這種情況真出現在生產上,那肯定屬于T1級別的重大Bug了
我們常用的法子就是先從緩存中取數據,如果緩存中取不到就直接通過數據庫來取數據,如果取不到,我們可以將key和value都是null寫入到緩存中,設置一定的時間,可以有效的防止惡意用戶反復用同一個ID來暴力攻擊,其實我們也可以在網關層做出相應的控制,因為用戶不可能在短時間內做出大量的多次請求的,當出現非正常頻率的請求的IP或者機器的時候,可以對這些IP和機器進行限制
緩存擊穿這種問題,其實最簡單的辦法就是設置緩存永不過期就好了,這應該是最簡單粗暴的方法了,或者通過互斥鎖也是可以解決這種
布隆過濾器
在redis中其實還有一個高級點的用法,布隆過濾器Bloom Filter,這個也可以很好的防止緩存穿透的發生,可以說這個就是為了防止這種情況而出生,利用極小的空間可以表示出大量的數據是否存在,但是這個是有一定的缺點的,缺點就是會存在一定的誤判率
布隆過濾器可以利用其高效的數據結構和算法快速的判斷出你操作的這個key在數據庫中是否存在,不存在直接return就好了,也就不用達到DB了,這樣就可以很好的避免緩存穿透的問題
即使很多IP同時發起攻擊,其實正常的redis集群也是頂得住的,小公司一般用的也是小的redis集群,不過一般他們也不感興趣對這些公司
簡單說下布隆過濾器的原理吧
布隆過濾器,首先想的是啥,你肯定想到的是為啥叫這個名字,玩過lol的小伙伴,肯定第一時間腦海里冒出來的是這個吧
圖片
經常玩輔助位置的小伙伴更是喜聞樂見,看見了這個春心開始蕩漾了,于是忍不住打開了桌面的lol,點擊了play,打完一把感覺隊友很氣,于是又開了一把...
好了好了,玩笑歸玩笑,來理解下這個布隆過濾器吧,我這里只是粗略的說一下原理,不詳細的解釋
布隆過濾器:一個很大的bit數組組成,系統在初始化的時候,會把數據庫已經存在的商品的ID通過哈希再映射到bit數組的位置上,最后便可以通過數組上相應的位置的值是否正確即可判斷是否存在商品
這樣說,可能有些晦澀
舉個例子:現在有一個很大的bit位數組,初始化全部位置為0
數據庫中存在商品1、2、3,然后我們有16個哈希函數,把1經過16個哈希函數映射得到16個哈希值,這16個哈希值會對應bit數組的16個位置,置為1;同樣的操作對2、3,也都會產生16個哈希值,也就是對應32個哈希位置,也都置為1;
最后會最多產生48個位置,為什么說是最多呢,因為1、2、3的映射可能會映射到同一個位置,所以說最極限的情況就是會產生48個位置的1
此時如果惡意請求攜帶商品為-1的請求打過來,也會對-1進行相應的操作,于是得到16個哈希值,對應bit數組中的16個位置,我們可以通過判斷這16個位置是否全是1來判斷數據庫中是否存在-1這個商品
你可能也看出來了,這樣會存在一定的誤判率,也就是存在一種極限情況,1、2、3產生的所有位置的映射值已經將-1的16個位置全部置為1了,當然這種情況也是比較少見的
一句話概述:有0一定不存在,但是全部為1,并不一定存在,所以存在一定的誤判率
不錯啊,小伙子,經過這么多輪的盤問,看來你對redis掌握的還可以
謝謝面試官的夸獎,請問offer什么時候能發到我的email里呢,畢竟我已經快一個多月沒有上班,沒有工資了,對于打工人來說,沒有工資是很難辦的
而且我這副業也還在起步階段,還在慢慢的寫,如果大家都能給個點贊給個關注,我也可以靠這個來恰點飯,這樣也不用這么著急要offer,也可以多面試幾輪,多給大家扯扯淡了(瘋狂暗示)
懂了,接下來我再問問你的設計模式這塊,就差不多了,因為我們公司對設計編碼這塊要求比較高,所以需要考察考察你的編碼設計能力
好嘞,沒問題,多謝面試官給透漏下一次的面試重點,我回去也好好準備準備
強行暗示下一系列
總結
其實這些問題算是類似的問題,也算是比較常見的問題,不要把這三個搞混了,這些問題應該是面試的香餑餑了,很多面試官都會問,即使不問,如果你能引出這些,并且給面試官講解請求,那面試官對你的好感也會大大增加
我們對于redis一般就是從三個時間段來解決各種問題的:
1、Redis高可用,哨兵、主從架構、集群,避免全盤直接崩潰的那種,這種主要是避免災難性的事故
2、過程中,本地ehcache緩存,Hystrix限流和降級來解決高流量,避免大流量直接打崩DB
3、之后的redis持久化:RDB和AOF,重啟自動加載數據,快速恢復緩存數據,合理的配置可以做到幾乎零丟失數據