Redis专题-缓存穿透、缓存雪崩、缓存击穿
一.緩存穿透
緩存穿透概念
緩存穿透是指查詢一個一定不存在的數據,在數據庫沒有,自然在緩存中也不會有。導致用戶查詢的時候,在緩存中找不到對應key的value,每次都要去數據庫再查詢一遍,如果從存儲層查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應用,這就是漏洞。
緩存穿透解決方案
有很多種方法可以有效地解決緩存穿透問題。
緩存空值
如果一個查詢返回的數據為空(不管是數據不存在,還是系統故障)我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過5分鐘。通過這個設置的默認值存放到緩存,這樣第二次到緩存中獲取就有值了,而不會繼續訪問數據庫。
采用布隆過濾器BloomFilter
在緩存之前加一層BloomFilter,將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。在查詢的時候先去BloomFilter去查詢key是否存在,如果不存在就直接返回,存在再去查詢緩存,緩存中沒有再去查詢數據庫。對BloomFilter有興趣的可以看我的另一篇文章教你用BitMap排序、查找和存儲大量數據。
二.緩存雪崩
緩存雪崩概念
緩存雪崩是指在我們設置緩存時采用了相同的過期時間,導致緩存在某一時刻同時失效,所有原本應該訪問緩存的請求都去查詢數據庫了,而對數據庫CPU和內存造成巨大壓力,嚴重的會造成數據庫宕機。
緩存雪崩解決方案
設置不同的過期時間,讓緩存失效的時間點盡量均勻
在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重復率就會降低,就很難引發集體失效的事件。
考慮用隊列或者鎖讓程序執行在壓力范圍之內,當然這種方案可能會影響并發量;
熱點數據可以考慮不失效。
三.緩存擊穿
緩存擊穿概念
在平常高并發的系統中,大量的請求同時查詢一個key,此時這個key正好失效了,就會導致大量的請求都打到數據庫上面去,造成數據庫請求量過大,壓力劇增,這種現象我們稱為緩存擊穿。
緩存擊穿解決方案
使用互斥鎖(mutex key)
業界比較常用的做法,是使用mutex。簡單地來說,就是在緩存失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作并回設緩存,否則,就重試整個get緩存的方法。
SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時候才設置,可以利用它來實現鎖的效果。redis2.6.1之前版本未實現setnx的過期時間,這里給出兩種版本代碼參考:
//2.6.1之前 String get(String key) { String value = redis.get(key); if (value == null) { if (redis.setnx(key_mutex, "1")) { // 3 min timeout to avoid mutex holder crash redis.expire(key_mutex, 3 * 60) value = db.get(key); redis.set(key, value); redis.delete(key_mutex); } else { //其他線程休息50毫秒后重試 Thread.sleep(50); get(key); } } } //2.6.1之后 String get(key) {String value = redis.get(key);if (value == null) { //代表緩存值過期//設置3min的超時,防止del操作失敗的時候,下次緩存過期一直不能load dbif (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表設置成功value = db.get(key);redis.set(key, value, expire_secs);redis.del(key_mutex);} else { //這個時候代表同時候的其他線程已經load db并回設到緩存了,這時候重試獲取緩存值即可sleep(50);get(key); //重試}} else {return value; }}永遠不過期
這里的“永遠不過期”包含兩層意思:
從實戰看,這種方法對于性能非常友好,唯一不足的就是構建緩存時候,其余線程(非構建緩存的線程)可能訪問的是老數據,但是對于一般的互聯網功能來說這個還是可以忍受。
猜你感興趣:
Redis專題-集群模式
Redis專題-持久化方式
Redis專題-底層數據結構與使用場景
Redis專題-緩存穿透、緩存雪崩、緩存擊穿
更多文章請點擊:更多…
總結
以上是生活随笔為你收集整理的Redis专题-缓存穿透、缓存雪崩、缓存击穿的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谈谈InnoDB下的记录锁,间隙锁,ne
- 下一篇: MYSQL专题-由简到繁理解索引结构