(目錄)
1、 緩存穿透問題的解決思路
緩存穿透 :
是 指
緩存穿透
,這樣緩存永遠不會生效,這些請求都會打到資料庫。
用戶端請求的資料在緩存中和資料庫中都不存在
常見的解決方案有兩種:
-
緩存空對象
優點:缺點:
- 實作簡單,維護友善
- 額外的記憶體消耗
- 可能造成短期的不一緻
-
布隆過濾
優點:缺點:
- 記憶體占用較少,沒有多餘key
- 實作複雜
- 存在誤判可能
緩存空對象思路分析:
當我們用戶端通路不存在的資料時,先請求redis,但是此時redis中沒有資料,此時會通路到資料庫,但是資料庫中也沒有資料,這個資料穿透了緩存,直擊資料庫,我們都知道資料庫能夠承載的并發不如redis這麼高,如果大量的請求同時過來通路這種不存在的資料,這些請求就都會通路到資料庫。 簡單的解決方案就是哪怕這個資料在資料庫中也不存在,我們也把這個資料存入到redis中去,這樣,下次使用者過來通路這個不存在的資料,那麼在redis中也能找到這個資料就不會進入到緩存了
布隆過濾:
布隆過濾器其實采用的是哈希思想來解決這個問題
,通過一個龐大的二進制數組,走哈希思想去判斷目前這個要查詢的這個資料是否存在,如果布隆過濾器判斷存在,則放行,這個請求會去通路redis,哪怕此時redis中的資料過期了,但是資料庫中一定存在這個資料,在資料庫中查詢出來這個資料後,再将其放入到redis中。
假設布隆過濾器判斷這個資料不存在,則直接傳回
這種
方式優點在于節約記憶體空間,存在誤判,誤判原因在于:布隆過濾器走的是哈希思想,隻要哈希思想,就可能存在哈希沖突
① 編碼解決商品查詢的緩存穿透問題:
核心思路如下:
- 在原來的邏輯中:
,這樣是會
我們如果發現這個資料在mysql中不存在,直接就傳回404了
的
存在緩存穿透問題
- 現在的邏輯中:
如果這個,我們不會傳回404 ,還是會
資料不存在
,
把這個資料寫入到Redis中,并且将value設定為空
,我們如果發現命中之後,
當再次發起查詢時
是否是null,如果是null,則是之前寫入的資料,證明是緩存穿透資料,如果不是,則直接傳回資料。
判斷value
代碼:
修改 ShopServiceImpl 中 queryShopById 方法 中的 不存在邏輯
/**
* 查詢商鋪
* @param id
* @return
*/
@Override
public Result queryShopById(Long id) {
// 1. 從 Redis 中查詢商鋪緩存
String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
// 2. 判斷是否存在
// 3. 存在 , 直接傳回
if(StrUtil.isNotBlank(shopJson)){
Shop shop=JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
//判斷命中空值 傳回 404
if(shopJson != null) {
// 傳回一個錯誤資訊
return Result.fail("商鋪不存在");
}
// 4. 不存在 ,根據 id 去資料庫查詢
Shop shop = getById(id);
// 5. 不存在 , 傳回 404
if(shop==null){
stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, "",CACHE_NULL_TTL,TimeUnit.MINUTES);
return Result.fail("商鋪不存在");
}
// 6. 存在 , 寫入 Redis
stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
return Result.ok(shop);
}
② 總結:
-
緩存穿透産生的原因是什麼?
使用者請求的資料在緩存中和資料庫中都不存在
,不斷發起這樣的請求,給資料庫帶來巨大壓力
-
?緩存穿透的解決方案有哪些
緩存null值
布隆過濾
,避免被猜測id規律
增強id的複雜度
- 做好資料的
基礎格式校驗
- 加強
使用者權限校驗
- 做好
熱點參數的限流
2、 緩存雪崩問題及解決思路
緩存雪崩:
- 給不同的Key的
TTL添加随機值
- 利用
提高服務的可用性
Redis叢集
- 給緩存業務添加
降級限流政策
- 給業務添加
多級緩存