(六)redis快取穿透,擊穿,雪崩以及解決方案

2022-07-03 08:27:11 字數 2918 閱讀 6804

專案中業務資料基本上都是存在關係型資料庫中,如:mysql,oracle,sqlserver等資料庫,專案上線初期,由於使用者規模還比較小,系統訪問量不大。關係性資料庫可以抗住併發較小的請求。隨著業務的增長使用者的增加系統整體的併發請求增大。關係型資料庫處理能力跟不上,在對資料庫做主從讀寫分離,分布式設計之前,引入快取可以有效提高系統整體的併發。如:redis非關係型資料庫。但是在使用快取redis的時候也存在相應的問題:快取穿透,擊穿,雪崩,如果不注意會導致併發壓力繞過快取直接落在資料庫上導致資料庫阻塞,崩潰等問題。

故障描述:

快取與資料庫都沒有的資料,發起大量訪問請求,對後端造成很大的壓力。要是有人利用不存在的key頻繁攻擊我們的應用,這就是漏洞。

解決方案:

1. 快取層快取空值

-快取太多空值,占用更多空間。(優化:給個空值過期時間)

-儲存層更新**了,快取層還是空值。(優化:後台設定時主動刪除空值,並快取把值進去)

//偽**

public object getproductlistnew()

cachevalue = cachehelper.get(cachekey);

if (cachevalue != null) else

cachehelper.add(cachekey, cachevalue, cachetime);

return cachevalue;}}

2. 布隆過濾器

-將資料庫中所有的查詢條件,放到布隆過濾器中。當乙個查詢請求來臨的時候,先經過布隆過濾器進行檢查,如果請求存在這個條件中,那麼繼續執行,如果不在,直接丟棄。

3. 介面引數驗籤

過濾掉特殊值,比如id= -1

故障描述:熱點單個key,過期,此時迎來高併發

對於一些設定了過期時間的key,如果這些key可能會在某些時間點被超高併發地訪問,是一種非常「熱點」的資料。這個時候,需要考慮乙個問題:快取被「擊穿」的問題,這個和快取雪崩的區別在於這裡針對某一key快取,前者則是很多key。

場景一:微博上,某某明星傳緋聞,兩個明星主頁被刷爆

快取在某個時間點過期的時候,恰好在這個時間點對這個key有大量的併發請求過來,這些請求發現快取過期一般都會從後端db載入資料並回設到快取,這個時候大併發的請求可能會瞬間把後端db壓垮。

解決方案:

使用互斥鎖(mutex key)

業界比較常用的做法,是使用mutex。簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用快取工具的某些帶成功操作返回值的操作(比如redis的setnx或者memcache的add)去set乙個mutex key,當操作返回成功時,再進行load db的操作並回設快取;否則,就重試整個get快取的方法。

public string get(key)  else 

} else

}

"提前"使用互斥鎖(mutex key):

在value內部設定1個超時值(timeout1), timeout1比實際的memcache timeout(timeout2)小。當從cache讀取到timeout1發現它已經過期時候,馬上延長timeout1並重新設定到cache。然後再從資料庫載入資料並設定到cache中。

"永遠不過期":這裡的「永遠不過期」包含兩層意思:

從redis上看,確實沒有設定過期時間,這就保證了,不會出現熱點key過期問題,也就是「物理」不過期。

從功能上看,如果不過期,那不就成靜態的了嗎?所以我們把過期時間存在key對應的value裡,如果發現要過期了,通過乙個後台的非同步執行緒進行快取的構建,也就是「邏輯」過期。

資源保護:

採用netflix的hystrix,可以做資源的隔離保護主線程池,如果把這個應用到快取的構建也未嘗不可。

為即將過期的key,續命:

快取中取值,發現即將過期,追加乙個小的時間值,延長有效期。

限流:比如說使用訊息佇列,讓流量在訊息佇列中囤積下,逐個消費,緩解後端壓力。

故障描述:快取雪崩是指在我們設定快取時採用了相同的過期時間,導致快取在某一時刻同時失效,請求全部**到db,db瞬時壓力過重雪崩。(與快取擊穿的區別在於這裡針對很多key快取,前者則是某乙個key)

場景一:同一時間點,快取全部失效:

比如:有的電商**在專案重啟時,將全部商品資訊加入快取中,並設定等長的有效期。到某一時間點,快取有效期過期,大量快取失效,如果遇上高併發,請求全部打在後端資料庫上。

場景二:穿透誘發雪崩:

短時間內大量的請求無法命中快取,請求穿透到資料庫,導致資料庫繁忙,請求超時。大量的請求超時還會引發更多的重試請求,更多的重試請求讓資料庫更加繁忙,這樣惡性迴圈導致系統雪崩。

解決方案:

熱點資料永不過期,資料庫更新時同步更新快取 (如:電商首頁資訊)

互斥鎖排隊

根據key獲取value值為空時,鎖上,從資料庫中load資料後再釋放鎖。若其它執行緒獲取鎖失敗,則等待一段時間後重試。這裡要注意,分布式環境中要使用分布式鎖(redisson),單機的話用普通的鎖(synchronized、lock)。

設定過期標誌更新快取

//偽**

public object getproductlistnew() else );

return cachevalue;}}

參考:

參考:

Redis快取穿透,穿透擊穿,快取雪崩

乙個一定不存在快取及查詢不到的資料,由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。有很多種方法可以有效地解決快取穿透問題,最常見的則是採用布隆過濾器,將所有可能存在的資料雜湊到乙個足夠大的bit...

redis 快取穿透 擊穿 雪崩

介面層增加校驗,如使用者鑑權校驗,id做基礎校驗,id 0的直接攔截 從快取取不到的資料,在資料庫中也沒有取到,這時也可以將key value對寫為key null,快取有效時間可以設定短點,如30秒 設定太長會導致正常情況也沒法使用 這樣可以防止攻擊使用者反覆用同乙個id暴力攻擊 public o...

redis快取穿透,擊穿,雪崩

快取穿透 描述 快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷發起請求,多來自於黑客攻擊。由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。在流量大時,可能db就掛掉了,要是有人利用不存在的k...