【緩存】緩存穿透、緩存雪崩、緩存擊穿

原文:https://www.cnblogs.com/raichen/p/7750165.htm

緩存穿透

概念

緩存穿透是指查詢一個一定不存在的數據,由於緩存是不命中時需要從數據庫查詢,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,造成緩存穿透。

解決辦法

  1. 布隆過濾器。布隆過濾器原理參考之前文章。我之前在想我們的系統是分佈式的,如果布隆過濾器的bitMap不準確怎麼辦,後來一想,本來布隆過濾器就存在誤判率在這個case下面是可以容忍誤判的。
  2. 講不存在的key緩存一個默認值。要是有人利用僞造的ID攻擊我們的應用。可以將這個不存在的key預先設定一個值。 比如,”key” , “NULL”。 在返回這個NULL值的時候,我們的應用就可以認爲這是不存在的key,那我們的應用就可以決定是否繼續等待繼續訪問,還是放棄掉這次操作。如果繼續等待訪問,過一個時間輪詢點後,再次請求這個key,如果取到的值不再是NULL,則可以認爲這時候key有值了,從而避免了大量僞造的請求訪問數據庫。

緩存雪崩

概念

大量的key設置了相同的過期時間,導致在緩存在同一時刻全部失效,造成瞬時DB請求量大、壓力驟增,引起雪崩。

解決辦法

從業務層面。可以給緩存設置過期時間時加上一個隨機值時間,使得每個key的過期時間分佈開來,不會集中在同一時刻失效。

緩存擊穿(併發)

概念

高併發系統,如果一個緩存失效,存在多進程同時查詢DB,同時更新緩存。這對緩存和DB都是比較大的挑戰。

解決辦法

  1. 使用互斥鎖(mutex key): 這種解決方案思路比較簡單,就是隻讓一個線程構建緩存,其他線程等待構建緩存的線程執行完,重新從緩存獲取數據就可以了(如下圖)

緩存加鎖 如果是單機,可以用synchronized或者lock來處理,如果是分佈式環境可以用分佈式鎖就可以了(分佈式鎖,可以用memcache的add, redis的setnx, zookeeper的添加節點操作)。

  1. "提前"使用互斥鎖(mutex key): 在value內部設置1個超時值(timeout1), timeout1比實際的 timeout(timeout2)小。當從cache讀取到timeout1發現它已經過期時候,馬上延長timeout1並重新設置到cache。然後再從數據庫加載數據並設置到cache中。
  2. "永遠不過期": 這裏的“永遠不過期”包含兩層意思: (1) 從redis上看,確實沒有設置過期時間,這就保證了,不會出現熱點key過期問題,也就是“物理”不過期。 (2) 從功能上看,如果不過期,那不就成靜態的了嗎?所以我們把過期時間存在key對應的value裏,如果發現要過期了,通過一個後臺的異步線程進行緩存的構建,也就是“邏輯”過期

image 從實戰看,這種方法對於性能非常友好,唯一不足的就是構建緩存時候,其餘線程(非構建緩存的線程)可能訪問的是老數據,但是對於一般的互聯網功能來說這個還是可以忍受。很多內存中的緩存都是基於這種方式構建的。

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