1.redis雪崩产生原因:
某一段时间内,缓存集中过期失效。导致大量请求直接访问数据库,增加数据库压力甚至造成数据库崩溃。
redis服务器宕机(可能直接造成数据库崩溃)。
和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
2.redis雪崩常见解决方案:
1.通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
注意:加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法。
public Users getByUsers(Long id) {
// 1.先查询redis
String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
+ "-id:" + id;
String userJson = redisService.getString(key);
if (!StringUtils.isEmpty(userJson)) {
Users users = JSONObject.parseObject(userJson, Users.class);
return users;
}
Users user = null;
try {
lock.lock();
// 查询db
user = userMapper.getUser(id);
redisService.setSet(key, JSONObject.toJSONString(user));
} catch (Exception e) {
} finally {
lock.unlock(); // 释放锁
}
return user;
}
2.不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
3.做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。
4.采用mq消息中间件来存储操作数据库的 请求,每次数据库(消费者)只让指定数量的请求连接数据库,其余的则在消息队列中等待,当操作数据库成功后把值写入到redis缓存中,再返回给客户端。
3.redis缓存穿透产生原因:
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空。这样请求就绕过缓存直接查数据库,增加数据库的压力,这也是经常提的缓存命中率问题。
4.redis缓存穿透解决方案:
1.查询数据库没有找到值的时候,直接返回null,然后将null或者特定的字符写入redis缓存中。缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。
2.网关判定查询条件的规则 ,不符合规则的查询条件直接返回null。
3.布隆过滤器 :布隆过滤器是一种非常高效的数据结构,把所有数据库的value对应的key 存储到布隆过滤器里,几乎不消耗什么空间,而且查询也是相当的快!但是请注意,它只能判断 key 是否存在(而且会有一定的误差)。
5.缓存击穿产生原因:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
6.缓存击穿解决方案:
- 设置热点数据永远不过期。
- 加锁。