目录
缓存雪崩
解决方案:
缓存击穿
解决方案
缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
解决方案:
u
给不同的
Key
的
TTL
添加随机值
u
利用
Redis
集群提高服务的可用性
u
给缓存业务添加降级限流策略
u
给业务添加多级缓存
缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案
1.互斥锁
2.逻辑过期
互斥锁和逻辑回归的优缺点
互斥锁:
优点:
• 没有额外的内存消耗• 保证一致性• 实现简单缺点:
• 线程需要等待,性能受影响• 可能有死锁风险
逻辑回归:
优点:
• 线程无需等待,性能较好缺点:
• 不保证一致性• 有额外内存消耗• 实现复杂
使用互斥锁的形式解决缓存击穿
public Shop queryWithMutex(Long id) throws InterruptedException {
String key = CACHE_SHOP_KEY + id;
//1.从redis中查询店铺缓存
String jsonShop = stringRedisTemplate.opsForValue().get(key);
//2.判断是否存在
if (StrUtil.isNotBlank(jsonShop)) {
//3.存在,直接返回
return JSONUtil.toBean(jsonShop, Shop.class);
}
if ("".equals(jsonShop)) {
return null;
}
//4.不存在,重建缓存
//4.1 获取互斥锁
//shop为实体类
Shop shop = null;
try {
Boolean isLock = tryLock(LOCK_SHOP_KEY + id);
//4.2 判断是否获取成功
if (!isLock) {
//4.3 失败,则休眠并重试
Thread.sleep(50);
return queryWithPassThrough(id);
}
//4.4 成功,根据id查询数据库
shop = getById(id);
//5. 不存在 返回错误
if (shop == null) {
// 将空值放入redis
stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
return null;
}
// 6. 存在 写入 redis
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//7.释放互斥锁
unLock(LOCK_SHOP_KEY + id);
}
//8.返回
return shop;
}