1)缓存穿透(Cache Penetration):指查询一个不存在的数据,由于缓存中没有数据,
所以这个查询请求会直接穿过缓存层,到达数据库层,造成了数据库的压力。
攻击者可以通过构造恶意请求,使得缓存层无法命中任何数据,
从而导致请求直接访问数据库,从而引起数据库压力过大。
(2)缓存击穿(Cache Breakdown):指缓存中某个热点数据失效,此时有大量并发请求同时访问
这个失效的数据,导致这些请求直接访问数据库,造成数据库压力过大,
甚至导致数据库崩溃。通常是由于缓存中某个热点数据过期失效,
同时有大量并发请求访问该数据。
(3)缓存雪崩(Cache Avalanche):指缓存中大量的数据失效,导致大量请求直接访问数据库,
造成数据库压力
/**
* 互斥锁解决缓存击穿 queryWithMutex()
* @param id
* @return
*/
public Shop queryWithMutex(Long id) {
// 1.从redis查询商铺缓存
String key = CACHE_SHOP_KEY + id;
String shopJson = stringRedisTemplate.opsForValue().get(key);
// 2.判断是否存在
if (StrUtil.isNotBlank(shopJson)) {
return JSONUtil.toBean(shopJson, Shop.class);
}
// 判断空值
if (shopJson != null) {
// 返回一个错误信息
return null;
}
String lockKey = "lock:shop:" + id;
Shop shop = null;
try {
// 4.实现缓存重建
// 4.1获取互斥锁
boolean isLock = tryLock(lockKey);
// 4.2判断是否成功
if (!isLock) {
// 4.3失败,则休眠并重试
Thread.sleep(50);
// 递归
return queryWithMutex(id);
}
// 4.4成功,根据id查询数据库
shop = getById(id);
// 模拟延迟
Thread.sleep(200);
// 5.不存在,返回错误
if (shop == null) {
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 ex) {
throw new RuntimeException(ex);
} finally {
// 7.释放锁
unLock(lockKey);
}
// 8.返回
return shop;
}
过大。通常是由于缓存中大量的数据在同一时间失效,
导致大量请求直接访问数据库 缓存击穿解决方案互斥锁解决缓存击穿