1. 程式人生 > 其它 >redis 的雪崩、穿透和擊穿

redis 的雪崩、穿透和擊穿

快取雪崩

  對於系統 A,假設每天高峰期每秒 5000 個請求,本來快取在高峰期可以扛住每秒 4000 個請求,但是快取機器意外發生了全盤宕機。快取掛了,此時 1 秒 5000 個請求全部落資料庫,資料庫必然扛不住,它會報一下警,然後就掛了。此時,如果沒有采用什麼特別的方案來處理這個故障,DBA 很著急,重啟資料庫,但是資料庫立馬又被新的流量給打死了。 這就是快取雪崩。 快取雪崩的事前事中事後的解決方案如下:
  • 事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
  • 事中:本地 ehcache 快取 + hystrix 限流&降級,避免 MySQL 被打死。
  • 事後:redis 持久化,一旦重啟,自動從磁碟上載入資料,快速恢復快取資料。

快取穿透

     對於系統A,假設一秒 5000 個請求,結果其中 4000 個請求是黑客發出的惡意攻擊。 黑客發出的那 4000 個攻擊,快取中查不到,每次你去資料庫裡查,也查不到。 舉個栗子。資料庫 id 是從 1 開始的,結果黑客發過來的請求 id 全部都是負數。這樣的話,快取中不會有,請求每次都“視緩存於無物”,直接查詢資料庫。這種惡意攻擊場景的快取穿透就會直接把資料庫給打死。      解決方式,每次系統 A 從資料庫中只要沒查到,就寫一個空值到快取裡去,比如 set -999 UNKNOWN。然後設定一個過期時間,這樣的話,下次有相同的 key 來訪問的時候,在快取失效之前,都可以直接從快取中取資料。  

快取擊穿

  快取擊穿,就是說某個 key 非常熱點,訪問非常頻繁,處於集中式高併發訪問的情況,當這個 key 在失效的瞬間,大量的請求就擊穿了快取,直接請求資料庫,就像是在一道屏障上鑿開了一個洞。 不同場景下的解決方式可如下:
  • 若快取的資料是基本不會發生更新的,則可嘗試將該熱點資料設定為永不過期。
  • 若快取的資料更新不頻繁,且快取重新整理的整個流程耗時較少的情況下,則可以採用基於 redis、zookeeper 等分散式中介軟體的分散式互斥鎖,或者本地互斥鎖以保證僅少量的請求能請求資料庫並重新構建快取,其餘執行緒則在鎖釋放後能訪問到新快取。
  • 若快取的資料更新頻繁或者快取重新整理的流程耗時較長的情況下,可以利用定時執行緒在快取過期前主動的重新構建快取或者延後快取的過期時間,以保證所有的請求能一直訪問到對應的快取。