Java高併發快取架構,快取雪崩、快取穿透之謎

李紅歐巴發表於2019-04-10

面試題

瞭解什麼是 redis 的雪崩、穿透和擊穿?redis 崩潰之後會怎麼樣?系統該如何應對這種情況?如何處理 redis 的穿透?

面試官心理分析

其實這是問到快取必問的,因為快取雪崩和穿透,是快取最大的兩個問題,要麼不出現,一旦出現就是致命性的問題,所以面試官一定會問你。

面試題剖析

快取雪崩

對於系統 A,假設每天高峰期每秒 5000 個請求,本來快取在高峰期可以扛住每秒 4000 個請求,但是快取機器意外發生了全盤當機。快取掛了,此時 1 秒 5000 個請求全部落資料庫,資料庫必然扛不住,它會報一下警,然後就掛了。此時,如果沒有采用什麼特別的方案來處理這個故障,DBA 很著急,重啟資料庫,但是資料庫立馬又被新的流量給打死了。

這就是快取雪崩。

redis-caching-avalanche

大約在 3 年前,國內比較知名的一個網際網路公司,曾因為快取事故,導致雪崩,後臺系統全部崩潰,事故從當天下午持續到晚上凌晨 3~4 點,公司損失了幾千萬。

快取雪崩的事前事中事後的解決方案如下。

  • 事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
  • 事中:本地 ehcache 快取 + hystrix 限流&降級,避免 MySQL 被打死。
  • 事後:redis 持久化,一旦重啟,自動從磁碟上載入資料,快速恢復快取資料。

redis-caching-avalanche-solution

使用者傳送一個請求,系統 A 收到請求後,先查本地 ehcache 快取,如果沒查到再查 redis。如果 ehcache 和 redis 都沒有,再查資料庫,將資料庫中的結果,寫入 ehcache 和 redis 中。

限流元件,可以設定每秒的請求,有多少能通過元件,剩餘的未通過的請求,怎麼辦?走降級!可以返回一些預設的值,或者友情提示,或者空白的值。

好處:

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

快取穿透

對於系統A,假設一秒 5000 個請求,結果其中 4000 個請求是黑客發出的惡意攻擊。

黑客發出的那 4000 個攻擊,快取中查不到,每次你去資料庫裡查,也查不到。

舉個栗子。資料庫 id 是從 1 開始的,結果黑客發過來的請求 id 全部都是負數。這樣的話,快取中不會有,請求每次都“視快取於無物”,直接查詢資料庫。這種惡意攻擊場景的快取穿透就會直接把資料庫給打死。

redis-caching-penetration

解決方式很簡單,每次系統 A 從資料庫中只要沒查到,就寫一個空值到快取裡去,比如 set -999 UNKNOWN。然後設定一個過期時間,這樣的話,下次有相同的 key 來訪問的時候,在快取失效之前,都可以直接從快取中取資料。

快取擊穿

快取擊穿,就是說某個 key 非常熱點,訪問非常頻繁,處於集中式高併發訪問的情況,當這個 key 在失效的瞬間,大量的請求就擊穿了快取,直接請求資料庫,就像是在一道屏障上鑿開了一個洞。

解決方式也很簡單,可以將熱點資料設定為永遠不過期;或者基於 redis or zookeeper 實現互斥鎖,等待第一個請求構建完快取之後,再釋放鎖,進而其它請求才能通過該 key 訪問資料。

免費Java資料需要自己領取,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高併發分散式等教程,一共30G。
傳送門:mp.weixin.qq.com/s/JzddfH-7y…


相關文章