Redis雪崩和緩存穿透

緩存雪崩

緩存雪崩產生的原因

緩存雪崩通俗簡單的理解就是:由於原有緩存失效(或者數據未加載到緩存中),新緩存未到期間(緩存正常從Redis中獲取,如下圖)所有原本應該訪問緩存的請求都去查詢數據庫了,而對數據庫CPU和內存造成巨大壓力,嚴重的會造成數據庫宕機,造成系統的崩潰。
在這裏插入圖片描述

緩存失效的時候

在這裏插入圖片描述
解決方案

1:在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個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個都在阻塞的。同樣會導致用戶等待超時,這是個治標不治本的方法。
2:不同的key,設置不同的過期時間,讓緩存失效的時間點儘量均勻。
3:做二級緩存,A1爲原始緩存,A2爲拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置爲短期,A2設置爲長期(此點爲補充)
4.使用消息隊列

緩存穿透

緩存穿透是指用戶查詢數據,在數據庫沒有,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數據庫再查詢一遍,然後返回空。這樣請求就繞過緩存直接查數據庫,這也是經常提的緩存命中率問題。
解決的辦法就是:如果查詢數據庫也爲空,直接設置一個默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫,這種辦法最簡單粗暴。

把空結果,也給緩存起來,這樣下次同樣的請求就可以直接返回空了,即可以避免當查詢的值爲空時引起的緩存穿透。同時也可以單獨設置個緩存區域存儲空值,對要查詢的key進行預先校驗,然後再放行給後面的正常緩存處理邏輯。

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並做更新緩存操作。

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