你知道的越多无畔,你不知道的越多
點(diǎn)贊再看,養(yǎng)成習(xí)慣
本文 GitHub https://github.com/JavaFamily 上已經(jīng)收錄干签,有一線大廠面試點(diǎn)思維導(dǎo)圖贷揽,也整理了很多我的文檔,歡迎Star和完善镜悉,大家面試可以參照考點(diǎn)復(fù)習(xí)祟辟,希望我們一起有點(diǎn)東西。
前言
作為一個(gè)在互聯(lián)網(wǎng)公司面一次拿一次Offer的面霸侣肄,打敗了無數(shù)競爭對(duì)手旧困,每次都只能看到無數(shù)落寞的身影失望的離開,略感愧疚(請(qǐng)?jiān)试S我使用一下夸張的修辭手法)。
于是在一個(gè)寂寞難耐的夜晚吼具,我痛定思痛僚纷,決定開始寫互聯(lián)網(wǎng)技術(shù)棧面試相關(guān)的文章,希望能幫助各位讀者以后面試勢(shì)如破竹拗盒,對(duì)面試官進(jìn)行360°的反擊怖竭,吊打問你的面試官,讓一同面試的同僚瞠目結(jié)舌锣咒,瘋狂收割大廠Offer侵状!
所有文章的名字只是我的噱頭,我們應(yīng)該有一顆謙遜的心毅整,所以希望大家懷著空杯心態(tài)好好學(xué)趣兄,一起進(jìn)步。
一點(diǎn)感慨
本來都把稿子放到公眾號(hào)保存了悼嫉,洗澡的時(shí)候想了一下晚上的比賽艇潭,覺得還是打開電腦寫點(diǎn)東西,跟文章內(nèi)容沒關(guān)系戏蔑,只是一點(diǎn)個(gè)人的感慨蹋凝,不知道多少小伙伴看了昨天SKT VS G2的比賽,又不知道多少小伙伴還記得Faker手抖的那一幕总棵。
[圖片上傳失敗...(image-3f9f38-1575860003202)]
<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
不知道你們看了是什么感受鳍寂,我看到他手抖的時(shí)候我內(nèi)心也抖了,世界賽我支持的都是LPL的隊(duì)伍情龄,但是我喜歡李哥這個(gè)人迄汛,那種對(duì)勝利的執(zhí)著,這么多年了那種堅(jiān)持自己的堅(jiān)持骤视,這么多利益誘惑在面前卻只想要?jiǎng)倮鞍@樣的人我好喜歡啊,我想很多人也喜歡专酗。
可能就像很多網(wǎng)友說的那樣睹逃,英雄遲暮,但是我覺得他還是有點(diǎn)東西祷肯,就像很多人說我們程序員只能吃年輕飯一樣沉填,但是如果你堅(jiān)持自己的堅(jiān)持,做個(gè)腹有詩書氣自華的仔佑笋,我想最后肯定會(huì)得到自己的得到翼闹。
好了我也不煽情了,我們開始講技術(shù)吧允青。
正文
上一期吊打系列我們提到了Redis的基礎(chǔ)知識(shí),還沒看的小伙伴可以回顧一下
那提到Redis我相信各位在面試,或者實(shí)際開發(fā)過程中對(duì)緩存雪崩颠锉,穿透法牲,擊穿也不陌生吧,就算沒遇到過但是你肯定聽過琼掠,那三者到底有什么區(qū)別拒垃,我們又應(yīng)該怎么去防止這樣的情況發(fā)生呢,我們有請(qǐng)下一位受害者瓷蛙。
面試開始
一個(gè)大腹便便悼瓮,穿著格子襯衣的中年男子,拿著一個(gè)滿是劃痕的mac向你走來艰猬,看著快禿頂?shù)念^發(fā)横堡,心想著肯定是尼瑪頂級(jí)架構(gòu)師吧!但是我們腹有詩書氣自華冠桃,虛都不虛命贴。
小伙子我看你的簡歷上寫到了Redis,那么我們直接開門見山食听,直接懟常見的幾個(gè)大問題胸蛛,Redis雪崩了解么?
帥氣迷人的面試官您好樱报,我了解的葬项,目前電商首頁以及熱點(diǎn)數(shù)據(jù)都會(huì)去做緩存 ,一般緩存都是定時(shí)任務(wù)去刷新迹蛤,或者是查不到之后去更新的民珍,定時(shí)任務(wù)刷新就有一個(gè)問題。
舉個(gè)簡單的例子:如果所有首頁的Key失效時(shí)間都是12小時(shí)笤受,中午12點(diǎn)刷新的穷缤,我零點(diǎn)有個(gè)秒殺活動(dòng)大量用戶涌入,假設(shè)當(dāng)時(shí)每秒 6000 個(gè)請(qǐng)求箩兽,本來緩存在可以扛住每秒 5000 個(gè)請(qǐng)求津肛,但是緩存當(dāng)時(shí)所有的Key都失效了。此時(shí) 1 秒 6000 個(gè)請(qǐng)求全部落數(shù)據(jù)庫汗贫,數(shù)據(jù)庫必然扛不住身坐,它會(huì)報(bào)一下警,真實(shí)情況可能DBA都沒反應(yīng)過來就直接掛了落包。此時(shí)部蛇,如果沒用什么特別的方案來處理這個(gè)故障,DBA 很著急咐蝇,重啟數(shù)據(jù)庫涯鲁,但是數(shù)據(jù)庫立馬又被新的流量給打死了。這就是我理解的緩存雪崩。
我刻意看了下我做過的項(xiàng)目感覺再吊的都不允許這么大的QPS直接打DB去抹腿,不過沒慢SQL加上分庫岛请,大表分表可能還還算能頂,但是跟用了Redis的差距還是很大
同一時(shí)間大面積失效警绩,那一瞬間Redis跟沒有一樣崇败,那這個(gè)數(shù)量級(jí)別的請(qǐng)求直接打到數(shù)據(jù)庫幾乎是災(zāi)難性的,你想想如果打掛的是一個(gè)用戶服務(wù)的庫肩祥,那其他依賴他的庫所有的接口幾乎都會(huì)報(bào)錯(cuò)后室,如果沒做熔斷等策略基本上就是瞬間掛一片的節(jié)奏,你怎么重啟用戶都會(huì)把你打掛混狠,等你能重啟的時(shí)候岸霹,用戶早就睡覺去了,并且對(duì)你的產(chǎn)品失去了信心檀蹋,什么垃圾產(chǎn)品松申。
面試官摸了摸自己的頭發(fā),嗯還不錯(cuò)俯逾,那這種情況咋整贸桶?你都是怎么去應(yīng)對(duì)的?
處理緩存雪崩簡單桌肴,在批量往Redis存數(shù)據(jù)的時(shí)候皇筛,把每個(gè)Key的失效時(shí)間都加個(gè)隨機(jī)值就好了,這樣可以保證數(shù)據(jù)不會(huì)在同一時(shí)間大面積失效坠七,我相信水醋,Redis這點(diǎn)流量還是頂?shù)米〉摹?/p>
setRedis(Key,value彪置,time + Math.random() * 10000)拄踪;
如果Redis是集群部署,將熱點(diǎn)數(shù)據(jù)均勻分布在不同的Redis庫中也能避免全部失效的問題拳魁,不過本渣我在生產(chǎn)環(huán)境中操作集群的時(shí)候惶桐,單個(gè)服務(wù)都是對(duì)應(yīng)的單個(gè)Redis分片,是為了方便數(shù)據(jù)的管理潘懊,但是也同樣有了可能會(huì)失效這樣的弊端姚糊,失效時(shí)間隨機(jī)是個(gè)好策略。
或者設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期授舟,有更新操作就更新緩存就好了(比如運(yùn)維更新了首頁商品救恨,那你刷下緩存就完事了,不要設(shè)置過期時(shí)間)释树,電商首頁的數(shù)據(jù)也可以用這個(gè)操作肠槽,保險(xiǎn)擎淤。
那你了解緩存穿透和擊穿么,可以說說他們跟雪崩的區(qū)別么秸仙?
嗯揉燃,了解,我先說一下緩存穿透吧筋栋,緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù),而用戶不斷發(fā)起請(qǐng)求正驻,我們數(shù)據(jù)庫的 id 都是1開始自增上去的弊攘,如發(fā)起為id值為 -1 的數(shù)據(jù)或 id 為特別大不存在的數(shù)據(jù)。這時(shí)的用戶很可能是攻擊者姑曙,攻擊會(huì)導(dǎo)致數(shù)據(jù)庫壓力過大襟交,嚴(yán)重會(huì)擊垮數(shù)據(jù)庫。
小點(diǎn)的單機(jī)系統(tǒng)伤靠,基本上用postman就能搞死捣域,比如我自己買的阿里云服務(wù)
像這種你如果不對(duì)參數(shù)做校驗(yàn),數(shù)據(jù)庫id都是大于0的宴合,我一直用小于0的參數(shù)去請(qǐng)求你焕梅,每次都能繞開Redis直接打到數(shù)據(jù)庫,數(shù)據(jù)庫也查不到卦洽,每次都這樣贞言,并發(fā)高點(diǎn)就容易崩掉了。
至于緩存擊穿嘛阀蒂,這個(gè)跟緩存雪崩有點(diǎn)像该窗,但是又有一點(diǎn)不一樣,緩存雪崩是因?yàn)榇竺娣e的緩存失效蚤霞,打崩了DB酗失,而緩存擊穿不同的是緩存擊穿是指一個(gè)Key非常熱點(diǎn),在不停的扛著大并發(fā)昧绣,大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問规肴,當(dāng)這個(gè)Key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存滞乙,直接請(qǐng)求數(shù)據(jù)庫奏纪,就像在一個(gè)完好無損的桶上鑿開了一個(gè)洞。
面試官露出欣慰的眼光斩启,那他們分別怎么解決
緩存穿透我會(huì)在接口層增加校驗(yàn)序调,比如用戶鑒權(quán)校驗(yàn),參數(shù)做校驗(yàn)兔簇,不合法的參數(shù)直接代碼Return发绢,比如:id 做基礎(chǔ)校驗(yàn)硬耍,id <=0的直接攔截等。
這里我想提的一點(diǎn)就是边酒,我們?cè)陂_發(fā)程序的時(shí)候都要有一顆“不信任”的心经柴,就是不要相信任何調(diào)用方,比如你提供了API接口出去墩朦,你有這幾個(gè)參數(shù)坯认,那我覺得作為被調(diào)用方,任何可能的參數(shù)情況都應(yīng)該被考慮到氓涣,做校驗(yàn)牛哺,因?yàn)槟悴幌嘈耪{(diào)用你的人,你不知道他會(huì)傳什么參數(shù)給你劳吠。
舉個(gè)簡單的例子引润,你這個(gè)接口是分頁查詢的,但是你沒對(duì)分頁參數(shù)的大小做限制痒玩,調(diào)用的人萬一一口氣查 Integer.MAX_VALUE 一次請(qǐng)求就要你幾秒淳附,多幾個(gè)并發(fā)你不就掛了么?是公司同事調(diào)用還好大不了發(fā)現(xiàn)了改掉蠢古,但是如果是黑客或者競爭對(duì)手呢奴曙?在你雙十一當(dāng)天就調(diào)你這個(gè)接口會(huì)發(fā)生什么,就不用我說了吧草讶。這是之前的Leader跟我說的缆毁,我覺得大家也都應(yīng)該了解下。
從緩存取不到的數(shù)據(jù)到涂,在數(shù)據(jù)庫中也沒有取到脊框,這時(shí)也可以將對(duì)應(yīng)Key的Value對(duì)寫為null、位置錯(cuò)誤践啄、稍后重試這樣的值具體取啥問產(chǎn)品浇雹,或者看具體的場(chǎng)景,緩存有效時(shí)間可以設(shè)置短點(diǎn)屿讽,如30秒(設(shè)置太長會(huì)導(dǎo)致正常情況也沒法使用)昭灵。
這樣可以防止攻擊用戶反復(fù)用同一個(gè)id暴力攻擊,但是我們要知道正常用戶是不會(huì)在單秒內(nèi)發(fā)起這么多次請(qǐng)求的伐谈,那網(wǎng)關(guān)層Nginx本渣我也記得有配置項(xiàng)烂完,可以讓運(yùn)維大大對(duì)單個(gè)IP每秒訪問次數(shù)超出閾值的IP都拉黑。
那你還有別的辦法么诵棵?
還有我記得Redis還有一個(gè)高級(jí)用法布隆過濾器(Bloom Filter)這個(gè)也能很好的防止緩存穿透的發(fā)生抠蚣,他的原理也很簡單就是利用高效的數(shù)據(jù)結(jié)構(gòu)和算法快速判斷出你這個(gè)Key是否在數(shù)據(jù)庫中存在,不存在你return就好了履澳,存在你就去查了DB刷新KV再return嘶窄。
那又有小伙伴說了如果黑客有很多個(gè)IP同時(shí)發(fā)起攻擊呢怀跛?這點(diǎn)我一直也不是很想得通,但是一般級(jí)別的黑客沒這么多肉雞柄冲,再者正常級(jí)別的Redis集群都能抗住這種級(jí)別的訪問的吻谋,小公司我想他們不會(huì)感興趣的。把系統(tǒng)的高可用做好了现横,集群還是很能頂?shù)摹?/p>
緩存擊穿的話漓拾,設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期〗潇簦或者加上互斥鎖就能搞定了
作為暖男晦攒,代碼我肯定幫你們準(zhǔn)備好了
面試結(jié)束
嗯嗯還不錯(cuò),三個(gè)點(diǎn)都回答得很好得哆,今天也不早了,面試就先到這里哟旗,明天你再過來二面我繼續(xù)問一下你關(guān)于Redis集群高可用贩据,主從同步,哨兵等知識(shí)點(diǎn)的問題闸餐。
暈居然還有下一輪面試1チ痢(強(qiáng)行下一期的伏筆哈哈)但是為了offer還是得舔,嗯嗯舍沙,好的帥氣面試官近上。
能回答得這么全面這么細(xì)節(jié)還是忍不住點(diǎn)贊
(暗示點(diǎn)贊,每次都看了不點(diǎn)贊拂铡,你們想白嫖我么壹无?你們好壞喲,不過我喜歡)
總結(jié)
我們玩歸玩感帅,鬧歸鬧斗锭,別拿面試開玩笑。
本文簡單的介紹了失球,Redis的雪崩岖是,擊穿,穿透实苞,三者其實(shí)都差不多豺撑,但是又有一些區(qū)別,在面試中其實(shí)這是問到緩存必問的黔牵,大家不要把三者搞混了聪轿,因?yàn)榫彺嫜┍馈⒋┩负蛽舸┗郑蔷彺孀畲蟮膯栴}屹电,要么不出現(xiàn)阶剑,一旦出現(xiàn)就是致命性的問題,所以面試官一定會(huì)問你危号。
大家一定要理解是怎么發(fā)生的牧愁,以及是怎么去避免的,發(fā)生之后又怎么去搶救外莲,你可以不是知道很深入猪半,但是你不能一點(diǎn)都不去想,面試有時(shí)候不一定是對(duì)知識(shí)面的拷問偷线,或許是對(duì)你的態(tài)度的拷問磨确,如果你思路清晰,然后知其然還知其所以然那就很贊声邦,還知道怎么預(yù)防那來上班吧乏奥。
最后暖男我繼續(xù)給你們做個(gè)小的技術(shù)總結(jié):
一般避免以上情況發(fā)生我們從三個(gè)時(shí)間段去分析下:
事前:Redis 高可用,主從+哨兵亥曹,Redis cluster邓了,避免全盤崩潰。
事中:本地 ehcache 緩存 + Hystrix 限流+降級(jí)媳瞪,避免** MySQL** 被打死骗炉。
事后:Redis 持久化 RDB+AOF,一旦重啟蛇受,自動(dòng)從磁盤上加載數(shù)據(jù)句葵,快速恢復(fù)緩存數(shù)據(jù)。
上面的幾點(diǎn)我會(huì)在吊打系列Redis篇全部講一下這個(gè)月應(yīng)該可以吧Redis更完兢仰,限流組件乍丈,可以設(shè)置每秒的請(qǐng)求,有多少能通過組件把将,剩余的未通過的請(qǐng)求诗赌,怎么辦?走降級(jí)秸弛!可以返回一些默認(rèn)的值铭若,或者友情提示,或者空白的值递览。
好處:
數(shù)據(jù)庫絕對(duì)不會(huì)死叼屠,限流組件確保了每秒只有多少個(gè)請(qǐng)求能通過。 只要數(shù)據(jù)庫不死绞铃,就是說镜雨,對(duì)用戶來說,3/5 的請(qǐng)求都是可以被處理的儿捧。 只要有 3/5 的請(qǐng)求可以被處理荚坞,就意味著你的系統(tǒng)沒死挑宠,對(duì)用戶來說,可能就是點(diǎn)擊幾次刷不出來頁面颓影,但是多點(diǎn)幾次各淀,就可以刷出來一次。
這個(gè)在目前主流的互聯(lián)網(wǎng)大廠里面是最常見的诡挂,你是不是好奇碎浇,某明星爆出什么事情,你發(fā)現(xiàn)你去微博怎么刷都空白界面璃俗,但是有的人又直接進(jìn)了奴璃,你多刷幾次也出來了,現(xiàn)在知道了吧城豁,那是做了降級(jí)苟穆,犧牲部分用戶的體驗(yàn)換來服務(wù)器的安全,可還行唱星?
點(diǎn)關(guān)注雳旅,不迷路
好了各位,以上就是這篇文章的全部內(nèi)容了魏颓,能看到這里的人呀,都是人才吱晒。
我后面會(huì)每周都更新幾篇一線互聯(lián)網(wǎng)大廠面試和常用技術(shù)棧相關(guān)的文章甸饱,非常感謝人才們能看到這里,如果這個(gè)文章寫得還不錯(cuò)仑濒,覺得「敖丙」我有點(diǎn)東西的話 求點(diǎn)贊?? 求關(guān)注?? 求分享?? 對(duì)暖男我來說真的 非常有用L净啊!墩瞳!
創(chuàng)作不易驼壶,各位的支持和認(rèn)可,就是我創(chuàng)作的最大動(dòng)力喉酌,我們下篇文章見热凹!
敖丙 | 文 【原創(chuàng)】
如果本篇博客有任何錯(cuò)誤,請(qǐng)批評(píng)指教泪电,不勝感激 般妙!
文章每周持續(xù)更新,可以微信搜索「 三太子敖丙 」第一時(shí)間閱讀和催更(比博客早一到兩篇喲)相速,本文 GitHub https://github.com/JavaFamily 已經(jīng)收錄碟渺,有一線大廠面試點(diǎn)思維導(dǎo)圖,也整理了很多我的文檔突诬,歡迎Star和完善苫拍,大家面試可以參照考點(diǎn)復(fù)習(xí)芜繁,希望我們一起有點(diǎn)東西。