4、總結
一般企業都會用到mysql等關係型資料庫,當訪問量不大的時候還可以支撐;當併發量高的時候,比如商品搶購或者主頁訪問瞬間較大的時候,請求直接到達db,可能會導致系統效能急劇下降以致癱瘓。db是面向磁碟的,磁碟io是比較重的操作,效能較低。為了克服上述的問題,通常需要在客戶端和db之間引入一層快取nosql技術,這是一種基於記憶體的資料庫,並提供一定的持久化功能,比如redis。但是引入快取之後,又有可能出現快取穿透等問題。
快取穿透:key對應的資料在資料來源並不存在,每次針對此key的請求從快取獲取不到,請求都會到資料來源,從而可能壓垮資料來源。比如用乙個不存在的使用者id獲取使用者資訊,不論快取還是資料庫都沒有,若黑客利用此漏洞進行攻擊可能壓垮資料庫。
快取擊穿:key對應的資料存在,但在redis中過期,此時若有大量併發請求過來,這些請求發現快取過期一般都會從後端db載入資料並回設到快取,這個時候大併發的請求可能會瞬間把後端db壓垮。
快取雪崩:當快取伺服器重啟或者大量快取集中在某乙個時間段失效,這樣在失效的時候,也會給後端系統(比如db)帶來很大壓力。
查詢乙個一定不存在的資料,快取不命中,最終達到db,查詢不到資料又不寫入快取,導致每次都要查db,失去快取的意義。
方案:布隆過濾器,維護乙個足夠大的bitmap,不存在的key一定會被攔截到,降低對底層db的查詢壓力
簡單粗暴的方法,如果從db重查詢為空,則快取乙個預設的值代表空值,過期時間設定較短些,最長不超過5min
粗暴方式的偽**:
//偽**
public object getvalue()
cachevalue = redishelper.
get(cachekey);if
(cachevalue != null)
else
redishelper.
add(cachekey, cachevalue, cachetime)
;return cachevalue;
}}
熱點key(某些時間點被超高併發訪問)失效,請求直達db。
方案:設定永不過期,另起排程任務定時更新key的值
業界比較常用的做法,是使用mutex。簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用快取工具的某些帶成功操作返回值的操作(比如redis的setnx或者memcache的add)去set乙個mutex key,當操作返回成功時,再進行load db的操作並回設快取;否則,就重試整個get快取的方法。setnx,是「set if not exists」的縮寫,也就是只有不存在的時候才設定,可以利用它來實現鎖的效果。
互斥鎖偽**:
public string get
(key)
else
}else
}
與快取擊穿的區別在於這裡針對多個key,快取擊穿針對乙個key。
方案:加鎖排隊:減輕資料庫的壓力,並沒有提高系統吞吐量。假設在高併發下,快取重建期間key是鎖著的,這是過來1000個請求999個都在阻塞的。同樣會導致使用者等待超時,這是個治標不治本的方法!
設定過期標誌更新快取
為key設定不同的隨機的快取失效時間
設定過期標誌更新快取偽**
public object get()
else);
return cachevalue;
}}
解釋說明:
針對業務系統,永遠都是具體情況具體分析;一切不以業務為基礎的框架設計都是耍流氓,所以還是要具體問題具體分析,找出乙個最合適的方案。
參考:
Redis 快取穿透 快取擊穿 快取雪崩
快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷發起請求,如發起為id為小於0的資料或id為特別大等不存在的資料。這時的使用者很可能是攻擊者,攻擊會導致資料庫壓力過大。舉例 通過分類id查詢廣告集合 param categoryid 廣告分類id return 廣告集合 public listf...
Redis快取穿透 快取擊穿 快取雪崩
指的是,redis快取中和資料庫中都沒有的資料,使用者不斷向伺服器發起請求,導致資料庫壓力過大。一般的流程查詢流程存在redis快取穿透bug 沒獲取到資料,到資料庫中查詢 如果一直沒獲取和查詢到資料,使用者不斷發起請求,資料庫就會不斷地進行查詢操作,導致資料庫壓力增大,導致快取擊穿。解決方案 阻止...
REDIS快取雪崩 快取穿透 快取擊穿
快取雪崩 同一時刻有大量key失效,導致大量請求到資料庫 解決方案1 key失效時間加上隨機值,或者更高階的演算法分散失效時間。解決方案2 沒有資料時也cache下,過期時間可設定短點,不把過多請求打到db去 快取穿透 當查詢redis中沒有的資料時,該查詢會下沉到資料庫層,同時資料庫層也沒有該資料...