redis 在大型项目里应用广泛,但当访问量,并发达到一定量的同时也会存在不少问题,例如 缓存击穿,雪崩问题的诞生 ,应对此类问题可以使用以下方案
1.缓存击穿
大致逻辑:当取缓存取不到时,使用互斥锁 将 从db 中取数的逻辑 锁住,取出后的数据再次回设到缓存中,否则,就重试;
public String getRedisValueByKey(key) {
String value = redis.get(key);
if (value == null) { //setnx 只有不存在这个互斥锁的时候才设置
if (redis.setnx(mutex, 1, 60) == 1) {
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
} else {
sleep(50);
getRedisValueByKey(key); //重试
}
} else {
return value;
}
}
2.缓存穿透
先解释一下缓存穿透 当查一个并不存在(缓存和db都没有)的key存储,请求都会到数据源,从而可能压垮数据源 我们在看看上面缓存击穿的方案里,你会发现当缓存里没有,从而去数据库里取值的时候,不管取出来的是不是空值,我们都将它进行缓存,设置过期时间会很短,最长不超过五分钟
value = db.get(key);
if(Objects.isNull(value)){
redis.set(key, value, 5);
}else{
redis.set(key, value, expire_secs);
}
以上是第一种比较暴力点得方案,还有最常见的则是采用布隆过滤器
(可以使用 一些客户端工具包来构造布隆过滤器,例如java里的Redisson;如果服务是集群部署,这个需要做成分布式布隆过滤器)
3. 雪崩
一听名字就知道如果发生这个事儿就比较严重 雪崩大概意思就是当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。想想,当我们的应用大量数据都是先从缓存中取,取不到再去db取; 当缓存服务器宕机了,此刻,程序大量访问redis的请求会同一时间走db取数,这对底层系统的冲击非常可怕
3.1 避免设置的key 缓存时间在同时一刻失效
方案:在原有key的缓存有效时间加一段随机数,这样每一个key 的过期时间的重复率就能降低
3.2 为了减轻数据库访问压力
方案:加锁排队取数,但这种在高并发的时候会非常不好用,而且在分布式应用中还有分布式锁的问题,这种情况只能具体应用具体分析调优了