緩存雪崩、穿透、擊穿詳解

緩存處理流程

  • 前臺請求,後臺先從緩存中取數據,取到直接返回結果,取不到時從數據庫中取,數據庫取到更新緩存,並返回結果,數據庫也沒取到,那直接返回空結果。

redis雪崩

  • 緩存雪崩是指緩存中數據大批量到過期時間,而查詢數據量巨大,引起數據庫壓力過大甚至down機。和緩存擊穿不同的是緩存擊穿指併發查同一條數據,緩存雪崩是不同數據都過期了,很多數據都查不到從而查數據庫。

  • 目前電商首頁以及熱點數據都會做緩存,一般緩存都會定時任務去刷新,或者是查不到之後去更新的,定時任務刷新就是一個問題。

    • 舉例 如果所有首頁的失效時間都是12小時,中午12點刷新的,凌晨零點有一個秒殺活動,假設當時每秒6000個請求,本來緩存每秒可以抗住5000個請求,但是緩存當時所有key都已實效,此時每秒6000個請求全部落入mysql,數據庫必然抗不住,它會報一下警,實際上可能DBA(數據庫管理員)都沒反應過來就掛了。此時,如果沒用什麼特別的方案來處理這個故障,DBA 很着急,重啓數據庫,但是數據庫立馬又被新的流量給打死了。感覺再吊都不允許這麼大的QPS(高併發)直接打DB去,不過設慢SQL加上分庫,大表分表可能還算可以頂住,但是跟用來redis差距還是很大的
      在這裏插入圖片描述
      同一時間大面積失效,那一瞬間Redis跟沒有一樣,那這個數量級別的請求直接打到數據庫幾乎是災難性的,你想想如果打掛的是一個用戶服務的庫,那其他依賴他的庫所有的接口幾乎都會報錯,如果沒做熔斷等策略基本上就是瞬間掛一片的節奏,你怎麼重啓用戶都會把你打掛,等你能重啓的時候,用戶早就睡覺去了,並且對你的產品失去了信心,什麼垃圾產品。
  • 解決方法:批量往存數據的時候,把每個Key的失效時間都加個隨機值,這樣可以保證數據不會在同一時間大面積失效,我相信,Redis這點流量還是頂得住的。

  • 也可以用redis集羣部署,緩解單個壓力。

  • 設置熱點數據永遠不過期,有更新操作就更新緩存就好了。

緩存穿透

  • 緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷髮起請求,如發起爲id爲“-1”的數據或id爲特別大不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大。
  • 像這種你如果不對參數做校驗,數據庫id都是大於0的,我一直用小於0的參數去請求你,每次都能繞開Redis直接打到數據庫,數據庫也查不到,每次都這樣,併發高點就容易崩掉了。
  • 解決方法:接口層增加校驗,如用戶鑑權校驗,id做基礎校驗,id<=0的直接攔截。
  • 從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將key-value對寫爲key-null,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。這樣可以防止攻擊用戶反覆用同一個id暴力攻擊。

緩存擊穿

  • 緩存擊穿,這個跟緩存雪崩有點像,但是又有一點不一樣,緩存雪崩是因爲大面積的緩存失效,打崩了DB,而緩存擊穿不同的是緩存擊穿是指一個Key非常熱點,在不停的扛着大併發,大併發集中對這一個點進行訪問,當這個Key在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個完好無損的桶上鑿開了一個洞。
  • 解決方法:這樣可以防止攻擊用戶反覆用同一個id暴力攻擊,但是我們要知道正常用戶是不會在單秒內發起這麼多次請求的,那網關層Nginx記得有配置項,可以讓運維大大對單個IP每秒訪問次數超出閾值的IP都拉黑。

擴展:

這裏我想提的一點就是,我們在開發程序的時候都要有一顆“不信任”的心,就是不要相信任何調用方,比如你提供了API接口出去,你有這幾個參數,那我覺得作爲被調用方,任何可能的參數情況都應該被考慮到,做校驗,因爲你不相信調用你的人,你不知道他會傳什麼參數給你。
舉個簡單的例子,你這個接口是分頁查詢的,但是你沒對分頁參數的大小做限制,調用的人萬一一口氣查 Integer.MAX_VALUE 一次請求就要你幾秒,多幾個併發你不就掛了麼?是公司同事調用還好大不了發現了改掉,但是如果是黑客或者競爭對手呢?在你雙十一當天就調你這個接口會發生什麼,就不用我說了吧。這是之前的Leader跟我說的,我覺得大家也都應該瞭解下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章