了解什么是 redis 的雪崩、穿透和擊穿?redis 崩潰之后會(huì)怎么樣?系統(tǒng)該如何應(yīng)對(duì)這種情況?如何處理 redis 的穿透?

原文出處:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md
歡迎 star 關(guān)注 GitHub 項(xiàng)目最新動(dòng)態(tài)!

面試題

了解什么是 redis 的雪崩、穿透和擊穿?redis 崩潰之后會(huì)怎么樣?系統(tǒng)該如何應(yīng)對(duì)這種情況?如何處理 redis 的穿透?

面試官心理分析

其實(shí)這是問到緩存必問的,因?yàn)榫彺嫜┍篮痛┩?,是緩存最大的兩個(gè)問題,要么不出現(xiàn),一旦出現(xiàn)就是致命性的問題,所以面試官一定會(huì)問你。

面試題剖析

緩存雪崩

對(duì)于系統(tǒng) A,假設(shè)每天高峰期每秒 5000 個(gè)請(qǐng)求,本來緩存在高峰期可以扛住每秒 4000 個(gè)請(qǐng)求,但是緩存機(jī)器意外發(fā)生了全盤宕機(jī)。緩存掛了,此時(shí) 1 秒 5000 個(gè)請(qǐng)求全部落數(shù)據(jù)庫,數(shù)據(jù)庫必然扛不住,它會(huì)報(bào)一下警,然后就掛了。此時(shí),如果沒有采用什么特別的方案來處理這個(gè)故障,DBA 很著急,重啟數(shù)據(jù)庫,但是數(shù)據(jù)庫立馬又被新的流量給打死了。

這就是緩存雪崩。

redis-caching-avalanche.png

大約在 3 年前,國內(nèi)比較知名的一個(gè)互聯(lián)網(wǎng)公司,曾因?yàn)榫彺媸鹿剩瑢?dǎo)致雪崩,后臺(tái)系統(tǒng)全部崩潰,事故從當(dāng)天下午持續(xù)到晚上凌晨 3~4 點(diǎn),公司損失了幾千萬。

緩存雪崩的事前事中事后的解決方案如下。

  • 事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
  • 事中:本地 ehcache 緩存 + hystrix 限流&降級(jí),避免 MySQL 被打死。
  • 事后:redis 持久化,一旦重啟,自動(dòng)從磁盤上加載數(shù)據(jù),快速恢復(fù)緩存數(shù)據(jù)。
redis-caching-avalanche-solution.png

用戶發(fā)送一個(gè)請(qǐng)求,系統(tǒng) A 收到請(qǐng)求后,先查本地 ehcache 緩存,如果沒查到再查 redis。如果 ehcache 和 redis 都沒有,再查數(shù)據(jù)庫,將數(shù)據(jù)庫中的結(jié)果,寫入 ehcache 和 redis 中。

限流組件,可以設(shè)置每秒的請(qǐng)求,有多少能通過組件,剩余的未通過的請(qǐng)求,怎么辦?走降級(jí)!可以返回一些默認(rèn)的值,或者友情提示,或者空白的值。

好處:

  • 數(shù)據(jù)庫絕對(duì)不會(huì)死,限流組件確保了每秒只有多少個(gè)請(qǐng)求能通過。
  • 只要數(shù)據(jù)庫不死,就是說,對(duì)用戶來說,2/5 的請(qǐng)求都是可以被處理的。
  • 只要有 2/5 的請(qǐng)求可以被處理,就意味著你的系統(tǒng)沒死,對(duì)用戶來說,可能就是點(diǎn)擊幾次刷不出來頁面,但是多點(diǎn)幾次,就可以刷出來一次。

緩存穿透

對(duì)于系統(tǒng)A,假設(shè)一秒 5000 個(gè)請(qǐng)求,結(jié)果其中 4000 個(gè)請(qǐng)求是黑客發(fā)出的惡意攻擊。

黑客發(fā)出的那 4000 個(gè)攻擊,緩存中查不到,每次你去數(shù)據(jù)庫里查,也查不到。

舉個(gè)栗子。數(shù)據(jù)庫 id 是從 1 開始的,結(jié)果黑客發(fā)過來的請(qǐng)求 id 全部都是負(fù)數(shù)。這樣的話,緩存中不會(huì)有,請(qǐng)求每次都“視緩存于無物”,直接查詢數(shù)據(jù)庫。這種惡意攻擊場(chǎng)景的緩存穿透就會(huì)直接把數(shù)據(jù)庫給打死。

redis-caching-penetration.png

解決方式很簡(jiǎn)單,每次系統(tǒng) A 從數(shù)據(jù)庫中只要沒查到,就寫一個(gè)空值到緩存里去,比如 set -999 UNKNOWN。然后設(shè)置一個(gè)過期時(shí)間,這樣的話,下次有相同的 key 來訪問的時(shí)候,在緩存失效之前,都可以直接從緩存中取數(shù)據(jù)。

緩存擊穿

緩存擊穿,就是說某個(gè) key 非常熱點(diǎn),訪問非常頻繁,處于集中式高并發(fā)訪問的情況,當(dāng)這個(gè) key 在失效的瞬間,大量的請(qǐng)求就擊穿了緩存,直接請(qǐng)求數(shù)據(jù)庫,就像是在一道屏障上鑿開了一個(gè)洞。

解決方式也很簡(jiǎn)單,可以將熱點(diǎn)數(shù)據(jù)設(shè)置為永遠(yuǎn)不過期;或者基于 redis or zookeeper 實(shí)現(xiàn)互斥鎖,等待第一個(gè)請(qǐng)求構(gòu)建完緩存之后,再釋放鎖,進(jìn)而其它請(qǐng)求才能通過該 key 訪問數(shù)據(jù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容