《我們一起進大廠》系列-快取雪崩、擊穿、穿透

敖丙發表於2019-11-04

你知道的越多,你不知道的越多

點贊再看,養成習慣

GitHub上已經開源github.com/JavaFamily,有一線大廠面試點腦圖,歡迎Star和完善

一點感慨

本來都把稿子放到公眾號儲存了,洗澡的時候想了一下晚上的比賽,覺得還是開啟電腦寫點東西,跟文章內容沒關係,只是一點個人的感慨,不知道多少小夥伴看了昨天SKT VS G2的比賽,又不知道多少小夥伴還記得Faker手抖的那一幕。

不知道你們看了是什麼感受,我看到他手抖的時候我內心也抖了,世界賽我支援的都是LPL的隊伍,但是我喜歡李哥這個人,那種對勝利的執著,這麼多年了那種堅持自己的堅持,這麼多利益誘惑在面前卻只想要勝利,這樣的人我好喜歡啊,我想很多人也喜歡。

可能就像很多網友說的那樣,英雄遲暮,但是我覺得他還是有點東西,就像很多人說我們程式設計師只能吃年輕飯一樣,但是如果你堅持自己的堅持,做個腹有詩書氣自華的仔,我想最後肯定會得到自己的得到。

好了我也不煽情了,我們開始講技術吧。

正文

上一期吊打系列我們提到了Redis的基礎知識,還沒看的小夥伴可以回顧一下

《吊打面試官》系列-Redis基礎

那提到Redis我相信各位在面試,或者實際開發過程中對快取雪崩穿透擊穿也不陌生吧,就算沒遇到過但是你肯定聽過,那三者到底有什麼區別,我們又應該怎麼去防止這樣的情況發生呢,我們有請下一位受害者。

面試開始

一個大腹便便,穿著格子襯衣的中年男子,拿著一個滿是劃痕的mac向你走來,看著快禿頂的頭髮,心想著肯定是尼瑪頂級架構師吧!但是我們腹有詩書氣自華,虛都不虛。

小夥子我看你的簡歷上寫到了Redis,那麼我們直接開門見山,直接懟常見的幾個大問題,Redis雪崩瞭解麼?

帥氣迷人的面試官您好,我瞭解的,目前電商首頁以及熱點資料都會去做快取 ,一般快取都是定時任務去重新整理,或者是查不到之後去更新的,定時任務重新整理就有一個問題。

舉個簡單的例子:如果所有首頁的Key失效時間都是12小時,中午12點重新整理的,我零點有個秒殺活動大量使用者湧入,假設當時每秒 6000 個請求,本來快取在可以扛住每秒 5000 個請求,但是快取當時所有的Key都失效了。此時 1 秒 6000 個請求全部落資料庫,資料庫必然扛不住,它會報一下警,真實情況可能DBA都沒反應過來就直接掛了。此時,如果沒用什麼特別的方案來處理這個故障,DBA 很著急,重啟資料庫,但是資料庫立馬又被新的流量給打死了。這就是我理解的快取雪崩。

我刻意看了下我做過的專案感覺再吊的都不允許這麼大的QPS直接打DB去,不過沒慢SQL加上分庫,大表分表可能還還算能頂,但是跟用了Redis的差距還是很大

同一時間大面積失效,那一瞬間Redis跟沒有一樣,那這個數量級別的請求直接打到資料庫幾乎是災難性的,你想想如果打掛的是一個使用者服務的庫,那其他依賴他的庫所有的介面幾乎都會報錯,如果沒做熔斷等策略基本上就是瞬間掛一片的節奏,你怎麼重啟使用者都會把你打掛,等你能重啟的時候,使用者早就睡覺去了,並且對你的產品失去了信心,什麼垃圾產品。

面試官摸了摸自己的頭髮,嗯還不錯,那這種情況咋整?你都是怎麼去應對的?

處理快取雪崩簡單,在批量往Redis存資料的時候,把每個Key的失效時間都加個隨機值就好了,這樣可以保證資料不會在同一時間大面積失效,我相信,Redis這點流量還是頂得住的。

setRedis(Key,value,time + Math.random() * 10000);
複製程式碼

如果Redis是叢集部署,將熱點資料均勻分佈在不同的Redis庫中也能避免全部失效的問題,不過本渣我在生產環境中操作叢集的時候,單個服務都是對應的單個Redis分片,是為了方便資料的管理,但是也同樣有了可能會失效這樣的弊端,失效時間隨機是個好策略。

或者設定熱點資料永遠不過期,有更新操作就更新快取就好了(比如運維更新了首頁商品,那你刷下快取就完事了,不要設定過期時間),電商首頁的資料也可以用這個操作,保險。

那你瞭解快取穿透和擊穿麼,可以說說他們跟雪崩的區別麼?

嗯,瞭解,我先說一下快取穿透吧,快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷髮起請求,我們資料庫的 id 都是1開始自增上去的,如發起為id值為 -1 的資料或 id 為特別大不存在的資料。這時的使用者很可能是攻擊者,攻擊會導致資料庫壓力過大,嚴重會擊垮資料庫。

小點的單機系統,基本上用postman就能搞死,比如我自己買的阿里服務

像這種你如果不對引數做校驗,資料庫id都是大於0的,我一直用小於0的引數去請求你,每次都能繞開Redis直接打到資料庫,資料庫也查不到,每次都這樣,併發高點就容易崩掉了。

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

面試官露出欣慰的眼光,那他們分別怎麼解決

快取穿透我會在介面層增加校驗,比如使用者鑑權校驗,引數做校驗,不合法的引數直接程式碼Return,比如:id 做基礎校驗,id <=0的直接攔截等。

這裡我想提的一點就是,我們在開發程式的時候都要有一顆“不信任”的心,就是不要相信任何呼叫方,比如你提供了API介面出去,你有這幾個引數,那我覺得作為被呼叫方,任何可能的引數情況都應該被考慮到,做校驗,因為你不相信呼叫你的人,你不知道他會傳什麼引數給你。

舉個簡單的例子,你這個介面是分頁查詢的,但是你沒對分頁引數的大小做限制,呼叫的人萬一一口氣查 Integer.MAX_VALUE 一次請求就要你幾秒,多幾個併發你不就掛了麼?是公司同事呼叫還好大不了發現了改掉,但是如果是黑客或者競爭對手呢?在你雙十一當天就調你這個介面會發生什麼,就不用我說了吧。這是之前的Leader跟我說的,我覺得大家也都應該瞭解下。

從快取取不到的資料,在資料庫中也沒有取到,這時也可以將對應Key的Value對寫為null、位置錯誤、稍後重試這樣的值具體取啥問產品,或者看具體的場景,快取有效時間可以設定短點,如30秒(設定太長會導致正常情況也沒法使用)。

這樣可以防止攻擊使用者反覆用同一個id暴力攻擊,但是我們要知道正常使用者是不會在單秒內發起這麼多次請求的,那閘道器層Nginx本渣我也記得有配置項,可以讓運維大大對單個IP每秒訪問次數超出閾值的IP都拉黑。

那你還有別的辦法麼?

還有我記得Redis還有一個高階用法布隆過濾器(Bloom Filter)這個也能很好的防止快取穿透的發生,他的原理也很簡單就是利用高效的資料結構和演算法快速判斷出你這個Key是否在資料庫中存在,不存在你return就好了,存在你就去查了DB重新整理KV再return。

那又有小夥伴說了如果黑客有很多個IP同時發起攻擊呢?這點我一直也不是很想得通,但是一般級別的黑客沒這麼多肉雞,再者正常級別的Redis叢集都能抗住這種級別的訪問的,小公司我想他們不會感興趣的。把系統的高可用做好了,叢集還是很能頂的。

快取擊穿的話,設定熱點資料永遠不過期。或者加上互斥鎖就能搞定了
作為暖男,程式碼我肯定幫你們準備好了

面試結束

嗯嗯還不錯,三個點都回答得很好,今天也不早了,面試就先到這裡,明天你再過來二面我繼續問一下你關於Redis叢集高可用,主從同步,哨兵等知識點的問題。

暈居然還有下一輪面試!(強行下一期的伏筆哈哈)但是為了offer還是得舔,嗯嗯,好的帥氣面試官。

能回答得這麼全面這麼細節還是忍不住點贊

暗示點贊,每次都看了不點贊,你們想白嫖我麼?你們好壞喲,不過我喜歡

總結

我們玩歸玩,鬧歸鬧,別拿面試開玩笑。

本文簡單的介紹了,Redis雪崩擊穿穿透,三者其實都差不多,但是又有一些區別,在面試中其實這是問到快取必問的,大家不要把三者搞混了,因為快取雪崩、穿透和擊穿,是快取最大的問題,要麼不出現,一旦出現就是致命性的問題,所以面試官一定會問你。

大家一定要理解是怎麼發生的,以及是怎麼去避免的,發生之後又怎麼去搶救,你可以不是知道很深入,但是你不能一點都不去想,面試有時候不一定是對知識面的拷問,或許是對你的態度的拷問,如果你思路清晰,然後知其然還知其所以然那就很贊,還知道怎麼預防那來上班吧。

最後暖男我繼續給你們做個小的技術總結:

一般避免以上情況發生我們從三個時間段去分析下:

  • 事前:Redis 高可用,主從+哨兵,Redis cluster,避免全盤崩潰。

  • 事中:本地 ehcache 快取 + Hystrix 限流+降級,避免** MySQL** 被打死。

  • 事後:Redis 持久化 RDB+AOF,一旦重啟,自動從磁碟上載入資料,快速恢復快取資料。

上面的幾點我會在吊打系列Redis篇全部講一下這個月應該可以吧Redis更完,限流元件,可以設定每秒的請求,有多少能通過元件,剩餘的未通過的請求,怎麼辦?走降級!可以返回一些預設的值,或者友情提示,或者空白的值。

好處:

資料庫絕對不會死,限流元件確保了每秒只有多少個請求能通過。 只要資料庫不死,就是說,對使用者來說,3/5 的請求都是可以被處理的。 只要有 3/5 的請求可以被處理,就意味著你的系統沒死,對使用者來說,可能就是點選幾次刷不出來頁面,但是多點幾次,就可以刷出來一次。

這個在目前主流的網際網路大廠裡面是最常見的,你是不是好奇,某明星爆出什麼事情,你發現你去微博怎麼刷都空白介面,但是有的人又直接進了,你多刷幾次也出來了,現在知道了吧,那是做了降級,犧牲部分使用者的體驗換來服務的安全,可還行?

點關注,不迷路

好了各位,以上就是這篇文章的全部內容了,能看到這裡的人呀,都是人才

我後面會每週都更新幾篇一線網際網路大廠面試和常用技術棧相關的文章,非常感謝人才們能看到這裡,如果這個文章寫得還不錯,覺得「敖丙」我有點東西的話 求點贊? 求關注❤️ 求分享? 對暖男我來說真的 非常有用!!!

白嫖不好,創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文章見!

敖丙 | 文 【原創】

如果本篇部落格有任何錯誤,請批評指教,不勝感激 !


文章每週持續更新,可以微信搜尋「 三太子敖丙 」第一時間閱讀和催更(比部落格早一到兩篇喲),本文 GitHub github.com/JavaFamily 已經收錄,有一線大廠面試點思維導圖,也整理了很多我的文件,歡迎Star和完善,大家面試可以參照考點複習,希望我們一起有點東西。

相關文章