面對海量請求献雅,緩存設計還應該考慮哪些問題碉考?

從第一個緩存框架 Memcached 誕生以來,緩存就廣泛地存在于互聯網應用中挺身。如果你的應用流量很小侯谁,那么使用緩存可能并不需要做多余的考慮。但如果你的應用流量達到了成百上千萬章钾,那么你就不得不考慮深層次的緩存問題:緩存穿透墙贱、緩存擊穿與緩存雪崩

緩存穿透

緩存穿透是指查詢一個一定不存在的數據贱傀,因為這個數據不存在惨撇,所以永遠不會被緩存,所以每次請求都會去請求數據庫府寒。

例如我們請求一個 UserID 為 -1 的用戶數據魁衙,因為該用戶不存在报腔,所以該請求每次都會去讀取數據庫。在這種情況下剖淀,如果某些心懷不軌的人利用這個存在的漏洞去偽造大量的請求榄笙,那么很可能導致DB承受不了那么大的流量就掛掉了。

對于緩存穿透祷蝌,有幾種解決方案茅撞,一種是事前預防,一種是事后預防巨朦。

事前預防米丘。其實就是對所有請求都進行參數校驗,把絕大多數非法的請求抵擋在最外層糊啡。在我們舉的這個例子中拄查,那么就是做參數校驗,對于 UserID 小于 0 的請求全部拒絕棚蓄。但即使我們做了全面的參數校驗堕扶,還是可能存在漏網之魚,會出現一些我們沒想到的情況梭依。

例如我們的 UserID 是遞增的稍算,那么如果有人請求一個 UserID 很大的用戶信息(例如:1000000),而我們的 UserID 最大也就 10000役拴。這個時候糊探,你不可能限制 UserID 大于 1 萬的就是非法的,或者說大于 10 萬就是非法的河闰,所以該用戶ID肯定可以通過參數校驗科平。但該用戶確實不存在,所以每次請求都會去請求數據庫姜性。

其實上面只是我所能想到的一種情況瞪慧,我們沒想到的情況肯定還有很多。對于這些情況部念,我們能做的就是時候預防弃酌。

事后預防。事后預防說的就是當查詢到一個空的結果時印机,我們仍然將這個空的結果進行緩存矢腻,但是設置一個很短的過期時間(例如一分鐘)。在這里我們可以看到射赛,其實我們并沒有完全預防非法請求多柑,只不過是將非法請求的風險讓承受能力更強的redis去承擔,讓承受能力稍弱的數據庫更安全楣责。

通過上面這兩種處理方式竣灌,我們基本可以解決緩存穿透的問題聂沙。事前預防解決80%的非法請求,剩下的20%非法請求則使用Redis轉移風險初嘹。

緩存擊穿

如果你的應用中有一些訪問量很高的熱點數據及汉,我們一般會將其放在緩存中以提高訪問速度。另外屯烦,為了保持時效性坷随,我們通常還會設置一個過期時間。但是對于這些訪問量很高的KEY驻龟,我們需要考慮一個問題:當熱點KEY在失效的瞬間温眉,海量的請求會不會產生大量的數據庫請求,從而導致數據庫崩潰翁狐?

例如我們有一個業(yè)務 KEY类溢,該 KEY 的并發(fā)請求量為 10000。當該 KEY 失效的時候露懒,就會有 1 萬個線程會去請求數據庫更新緩存闯冷。這個時候如果沒有采取適當的措施,那么數據庫很可能崩潰懈词。

其實上面這個問題就是緩存擊穿的問題蛇耀,它發(fā)生在緩存KEY的過期瞬間。對于這種情況钦睡,現在常用的解決方式有這么兩種:互斥鎖蒂窒、永遠不過期躁倒。

互斥鎖

互斥鎖指的是在緩存KEY過期去更新的時候荞怒,先讓程序去獲取鎖,只有獲取到鎖的線程才有資格去更新緩存KEY秧秉。其他沒有獲取到鎖的線程則休眠片刻之后再次去獲取最新的緩存數據褐桌。通過這種方式,同一時刻永遠只有一個線程會去讀取數據庫象迎,這樣也就避免了海量數據庫請求對于數據庫的沖擊荧嵌。

而對于上面說到的鎖,我們可以使用緩存提供的一些原則操作來完成砾淌。例如對于 redis 緩存來說啦撮,我們可以使用其 SETNX 命令來完成。

public String get(key) {  
    String value = redis.get(key);  
    if (value == null) { //緩存過期  
        if (redis.setnx(key_mutex, 1, 1 * 60) == 1) {   
                value = db.get(key);  
                redis.set(key, value, expireTime);  
                redis.del(key_mutex);  
            } else {  
                //休眠片刻后重試
                sleep(50);  
                get(key);   
            }  
        } else {  
            return value;        
    }  
} 

上面的 key_mutex 其實就是一個普通的 KEY-VALUE 值汪厨,我們使用 setnx 命令去設置其值為 1赃春。如果這時候已經有人在更新緩存KEY了,那么 setnx 命令會返回 0劫乱,表示設置失敗织中。

永遠不過期

從緩存的角度來看锥涕,如果你設置了永遠不過期,那么就不會有海量請求數據庫的情形出現狭吼。此時我們一般通過新起一個線程的方式去定時將數據庫中的數據更新到緩存中层坠,更加成熟的方式是通過定時任務去同步緩存和數據庫的數據。

但這種方案會出現數據的延遲問題刁笙,也就是線程讀取到的數據并不是最新的數據破花。但對于一般的互聯網功能來說,些許的延遲還是能接受的疲吸。

緩存雪崩

緩存雪崩是指在我們設置緩存時采用了相同的過期時間旧乞,導致緩存在某一時刻同時失效,請求全部轉發(fā)到數據庫磅氨,最終導致數據庫瞬時壓力過大而崩潰尺栖。

例如我們有 1000 個KEY,而每個 KEY 的并發(fā)請求不大烦租,只有 10 次延赌。而緩存雪崩指的就是這 1000 個 KEY 在同一時間,同時失效叉橱,這個時候就突然有 1000 ** 10 = 一萬次查詢挫以。

緩存雪崩導致的問題一般很難排查,如果沒有事先預防窃祝,很可能要花很大力氣才能找得到原因掐松。對于緩存雪崩的情況,最簡單的方案就是在原有失效時間的基礎上增加一個隨機時間(例如1-5分鐘)粪小,這樣每個緩存過期時間的重復率就會降低大磺,從而減少緩存雪崩的發(fā)生。

總結

對于緩存穿透探膊、緩存擊穿杠愧、緩存雪崩這三個情景,許多人會搞不明白逞壁,甚至會混淆流济。

「緩存穿透」指的是請求不存在的數據,從而使得緩存形同虛設腌闯,緩存層被穿透了绳瘟。例如我們請求一個 UserID 為 -1 的用戶數據,因為該用戶不存在姿骏,所以該請求每次都會去讀取數據庫糖声。在這種情況下,如果某些心懷不軌的人利用這個存在的漏洞去偽造大量的請求,那么很可能導致DB承受不了那么大的流量就掛掉了姨丈。

「緩存擊穿」指的是并發(fā)量很高的 KEY畅卓,在該 KEY 失效的瞬間有很多請求同同時去請求數據庫,更新緩存蟋恬。例如我們有一個業(yè)務 KEY翁潘,該 KEY 的并發(fā)請求量為 10000。當該 KEY 失效的時候歼争,就會有 1 萬個線程會去請求數據庫更新緩存拜马。這個時候如果沒有采取適當的措施,那么數據庫很可能崩潰沐绒。

「緩存雪崩」則是指緩存在同一時間同時過期俩莽,就像所有雪塊同一時刻掉下來,像雪崩一樣乔遮。例如我們有 1000 個KEY扮超,而每個 KEY 的并發(fā)請求不大,只有 10 次蹋肮。而緩存雪崩指的就是這 1000 個 KEY 在同一時間出刷,同時失效,這個時候就突然有 1000 ** 10 = 一萬次查詢坯辩。

對于它們出現的情形馁龟,我們可以做一些總結:

  • 「緩存穿透」是業(yè)務層面的漏洞導致非法請求,與請求量漆魔、緩存失效沒關系坷檩。
  • 「緩存擊穿」則只會出現在熱點數據上,發(fā)生在緩存失效的瞬間改抡,與業(yè)務沒多大關系矢炼。
  • 「緩存雪崩」則是因為多個 KEY 同時失效,導致數據庫請求太多雀摘。非熱點數據也會導致緩存雪崩裸删,只要同時失效的 KEY 足夠多。

如果覺得文章還不錯阵赠,記得點贊評論,那我以后就會寫更多類似的文章肌稻!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末清蚀,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子爹谭,更是在濱河造成了極大的恐慌枷邪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诺凡,死亡現場離奇詭異东揣,居然都是意外死亡践惑,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門嘶卧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尔觉,“玉大人,你說我怎么就攤上這事芥吟≌焱” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵钟鸵,是天一觀的道長钉稍。 經常有香客問我,道長棺耍,這世上最難降的妖魔是什么贡未? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮蒙袍,結果婚禮上羞秤,老公的妹妹穿的比我還像新娘。我一直安慰自己左敌,他們只是感情好瘾蛋,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著矫限,像睡著了一般哺哼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叼风,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天取董,我揣著相機與錄音,去河邊找鬼无宿。 笑死茵汰,一個胖子當著我的面吹牛,可吹牛的內容都是我干的孽鸡。 我是一名探鬼主播蹂午,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼彬碱!你這毒婦竟也來了豆胸?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤巷疼,失蹤者是張志新(化名)和其女友劉穎晚胡,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡估盘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年瓷患,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遣妥。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡擅编,死狀恐怖,靈堂內的尸體忽然破棺而出燥透,到底是詐尸還是另有隱情沙咏,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布班套,位于F島的核電站肢藐,受9級特大地震影響,放射性物質發(fā)生泄漏吱韭。R本人自食惡果不足惜吆豹,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望理盆。 院中可真熱鬧痘煤,春花似錦、人聲如沸猿规。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姨俩。三九已至蘸拔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間环葵,已是汗流浹背调窍。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留张遭,地道東北人邓萨。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像菊卷,于是被迫代替她去往敵國和親缔恳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361