文章目录
一、缓存穿透 非法key
1. 现象
简单来说就是大量请求的key是不合理的,既不存在于缓存中,也不存在数据库中,这些请求全部直接到了数据库上,根本没经过缓存这一层,可能导致数据库宕机。
2. 解决方法
1)缓存无效key
如果缓存和数据库都查不到某个 key 的数据就写一个到 Redis 中去并设置过期时间
SET key value EX 10086
无法从根本上解决问题,且会让redis中存放大量无效key。如果一定要使用,key的过期时间设置的尽量短一点。
public String getObjectInclNullById(String key){
// 从redis中读取key
String cache = redisTemplate.opsForValue().get(key);
// 如果缓存中key不存在
if(StringUtil.isNullOrEmpty(cache)){
// 从数据库中读取
String value = stockMapper.findKey(key);
redisTemplate.opsForValue().set(key, value);
if(StringUtil.isNullOrEmpty(value)){
// 如果数据库中也没有,必须为key设置个过期时间
redisTemplate.expire(key,30, TimeUnit.MILLISECONDS);
}
return value;
}
return cache;
}
2) 布隆过滤器
布隆过滤器:判断一个给定的数据是否存在于海量数据之中
- 把所有可能存在的请求的值都存放在布隆过滤器中。
- 当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。
- 不存在的话,直接返回请求参数错误信息给客户端。
- 存在的话才会进行后续对缓存和数据库的查询。
注意:
布隆过滤器说某个元素存在,会小概率误判。
布隆过滤器说某个元素不存在,那一定不存在。
因为布隆过滤器是通过哈希判断,不同的字符串可能哈希出来的位置相同
二、缓存击穿 热点key过期
1. 现象
请求的 key 是热点数据 ,该数据存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。可能导致瞬时大量请求直接到了数据库,对数据库造成了巨大的压力,导致数据库宕机。
2. 解决方法
1) 设置热点数据永不过期或者过期时间比较长。
2) 针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。
3)请求数据库写数据到缓存之前,先获取互斥锁,保证只有一个请求会落到数据库上,减少数据库的压力。即分布式锁解决方案。
三、缓存雪崩:缓存同时大面积失效
1. 现象
缓存在同一时间大面积的失效,导致大量请求都直接落到了数据库上,对数据库造成了巨大的压力。
另外,缓存服务宕机也会导致缓存雪崩现象,导致所有的请求都落到了数据库上。
2. 解决方法
1) 针对redis服务不可用
- 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
- 限流,避免同时处理大量的请求。
2) 针对缓存大面积失效
- 设置不同的失效时间比如随机设置缓存的失效时间。
- 缓存永不失效(不太推荐,实用性太差)。
- 设置二级缓存。