Redis 缓存穿透、缓存击穿、缓存雪崩区别和解决方案

前言

设计一个缓存系统,不得不要考虑的问题就是:缓存穿透、缓存击穿与失效时的雪崩效应。

缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从储存层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到储存层去查询,失去了缓存的意义。在流量大时,可能DB挂掉,要是有人利用不存在的key频繁攻击我们的应用这就是漏洞

解决方案

方案一:布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力

方案二:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们让然把这个空结果进行缓存,但他的过期时间会很短,最长不超过5分钟

缓存雪崩

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬间压力过重导致雪崩

解决方案

扫描二维码关注公众号,回复: 10014244 查看本文章

缓存数据的过期时间随机设置,防止同一时间大量数据过期现象发生

如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中,分散压力

设置热点数据永远不过期

缓存击穿

缓存击穿是指缓存中没有这些数据但是数据库中有数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大的压力

解决方案

设置热点数据永远不过期

使用互斥锁

public String get(key){
    //缓存中读取数据
	String value = redis.get(key);
    //缓存中不存在
    if(value == null){//代表缓存之过期
        //加锁 设置3分钟的超时,防止del操作失败的时候,下次缓存过期一直不能load 数据库
        if(redis.setnx(key_mutex,1,3*60) == 1){
            //从数据库中获取数据
            value = db.get(key);
            //更新缓存
            redis.set(key,value,expire_secs);
            //释放锁
            redis.del(key_mutex);
        }else{//这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
            sleep(50);
            //重新尝试获取缓存
            value = redis.get(key);
        }
    }
    return value;
}
发布了270 篇原创文章 · 获赞 52 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/LuckFairyLuckBaby/article/details/103509336