1.缓存穿透
定义:
缓存穿透是指查询一个不存在的数据,由于缓存中没有该数据,请求会直接落到数据库上。如果大量这样的请求同时发生,数据库可能会被压垮。
原因:
- 恶意攻击: 攻击者故意请求大量不存在的数据。
- 业务逻辑问题:某些查询条件本身就不存在有效数据。
解决方案:
1.缓存空值:
- 如果查询结果为空,扔将空值缓存起来,并设置一个较短的过期时间。
if (data == null) {cache.put(key, "NULL", 60); // 缓存空值,过期时间为 60 秒
}
2.布隆过滤器(Bloom Filter):
使用布隆过滤器预先判断数据是否存在。如果布隆过滤器认为数据不存在,则直接返回,避免查询数据库。
if (!bloomFilter.mightContain(key)) {return null; // 数据肯定不存在
}
3.接口层校验:
- 在接口层请求参数进行校验,过滤掉明显非法的请求。
2.缓存击穿:
定义:
缓存击穿是指某个热点数据在缓存中过期后,大量请求同时涌入,直接访问数据库,导致数据库压力骤增。
原因:
- 热点数据突然失效。
- 大量请求同时访问该数据。
解决方案:
1.设置热点数据永不过期:
- 对于热点数据,可以设置永不过期,或者定期异步更新缓存。
2.互斥锁
if (cache.get(key) == null) {if (lock.tryLock()) { // 获取锁try {// 查询数据库并更新缓存cache.put(key, value);} finally {lock.unlock(); // 释放锁}} else {// 等待缓存更新完成Thread.sleep(100);return cache.get(key);}
}
3.提前更新缓存:
3.缓存雪崩:
定义:
缓存雪崩是指大量缓存数据在同一时间过期,导致大量请求直接访问数据库,数据库压力骤增,直接崩溃。
原因:
解决方案:
1.设置不同的过期时间:
int expireTime = 60 + new Random().nextInt(60); // 过期时间在 60-120 秒之间
cache.put(key, value, expireTime);
2.缓存高可用:
- 使用Redis集群或主从复制,确保缓存服务的高可用性。
- 比如:使用Redis Sentinel或Redis Cluster
3.限流和降级:
4.多级缓存:
if (localCache.get(key) != null) {return localCache.get(key);
} else if (distributedCache.get(key) != null) {localCache.put(key, distributedCache.get(key));return distributedCache.get(key);
} else {// 查询数据库并更新缓存
}