緩存雪崩
緩存雪崩通俗簡單的了解就是:由于原有緩存失效(或者資料未加載到緩存中),新緩存未到期間,所有原本應該通路緩存的請求都去查詢資料庫了,而對資料庫CPU和記憶體造成巨大壓力,嚴重的會造成資料庫當機,造成系統的崩潰。
redis 緩存雪崩解決方案
-
分布式鎖(本地鎖)
在緩存失效後,通過加鎖或者隊列來控制讀資料庫寫緩存的線程數量。比如對某個key隻允許一個線程查詢資料和寫緩存,其他線程等待。
@RequestMapping("/getUsers")
public Users getByUsers(Long id) {
// 1.先查詢redis
String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
+ "-id:" + id;
String userJson = redisService.getString(key);
if (!StringUtils.isEmpty(userJson)) {
Users users = JSONObject.parseObject(userJson, Users.class);
return users;
}
Users user = null;
try {
lock.lock();
// 查詢db
user = userMapper.getUser(id);
redisService.setSet(key, JSONObject.toJSONString(user));
} catch (Exception e) {
} finally {
lock.unlock(); // 釋放鎖
}
return user;
}
注意:加鎖排隊隻是為了減輕資料庫的壓力,并沒有提高系統吞吐量。假設在高并發下,緩存重建期間key是鎖着的,這是過來1000個請求999個都在阻塞的。同樣會導緻使用者等待逾時,這是個治标不治本的方法。
- 使用消息中間件 MQ 方式(最靠譜的方式),消息中間件方式可以解決高并發。如果大量請求進行通路的時候,如果 redis 沒有值的情況下,這個會将該消息存放在消息中間件中(異步)
- 一級和二級(ehcache+redis)緩存
- 均攤配置設定 redis key 的失效時間(比較靠譜),不同的key的失效時間都不同。
redis 緩存穿透
緩存穿透是指使用者查詢資料,在資料庫沒有,自然在緩存中也不會有。這樣就導緻使用者查詢的時候, 在緩存中找不到,每次都要去資料庫再查詢一遍,然後傳回空。這樣請求就繞過緩存直接查資料庫,這也是經常提的緩存命中率問題。
解決的辦法就是:如果查詢資料庫也為空,直接設定一個預設值存放到緩存,這樣第二次到緩沖中擷取就有值了,而不會繼續通路資料庫,這種辦法最簡單粗暴。
public String getByUsers2(Long id) {
// 1.先查詢redis
String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
+ "-id:" + id;
String userName = redisService.getString(key);
if (!StringUtils.isEmpty(userName)) {
return userName;
}
System.out.println("######開始發送資料庫DB請求########");
Users user = userMapper.getUser(id);
String value = null;
if (user == null) {
// 辨別為null
value = SIGN_KEY;
} else {
value = user.getName();
}
redisService.setString(key, value);
return value;
}
把空結果,也給緩存起來,這樣下次同樣的請求就可以直接傳回空了,即可以避免當查詢的值為空時引起的緩存穿透。同時也可以單獨設定個緩存區域存儲空值,對要查詢的key進行預先校驗,然後再放行給後面的正常緩存處理邏輯。
緩存擊穿
熱點key:某個key通路非常頻繁,當key失效的時候有大量線程來建構緩存,導緻負載增加,系統崩潰。
解決辦法:
- 使用鎖,單機用synchronized,lock等,分布式用分布式鎖。
- 緩存過期時間不設定,而是設定在key對應的value裡。如果檢測到存的時間超過過期時間則異步更新緩存。
- 在value設定一個比過期時間t0小的過期時間值t1,當t1過期的時候,延長t1并做更新緩存操作。