缓存穿透、缓存击穿、缓存雪崩的区别

一、缓存穿透:(即:缓存无数据,数据库也无数据)

  如黑客恶意攻击,使用缓存和数据库均没有的key进行不断请求,导致数据库压力过大。

解决方法:

1、对用户进行鉴权、对请求参数进行校验,不合理直接过滤。

2、对查询不到的数据也放到缓存,value为空,设置一定的过期时间。(不太常用,因为如果是随机key就不起作用,且占缓存)

3、使用布隆过滤器,快速判断key是否在数据库中存在,不存在直接返回。(最有效)

第1种是最常用的策略,第2种不太常用,因为如果是随机key就不起作用,且占缓存,第三种最简单有效。实际使用中,可以1、3相结合。

 

二、缓存击穿:(即:缓存无数据,数据库有数据,key比较集中)

  如高并发的情况下,热点数据缓存过期,这时候会导致大量请求读不到缓存同时读数据库,导致数据库负载过大。

解决方法:

1、设置热点数据永远不过期。

2、热点数据快过期时,通过另一个异步线程重新设置key。

3、当从缓存数据过期,重新从数据库加载数据到缓存的过程上互斥锁。

第1种的话,数据量大时,缓存量会比较大,第2种,很好理解,但是需要另外的逻辑去维护,会增加系统的复杂度。第3种,是比较常用的方式。

加载缓存时上互斥锁:

 1     public String get(String key) throws Exception {
 2         String value = redis.get(key);
 3         // 缓存过期
 4         if (value == null) {
 5             // 设置有效期,防止del操作失败时,缓存过期一直不能重新加载缓存
 6             if (redis.setnx(key_mutex, 1, 60)) {
 7                 // 从数据库加载缓存
 8                 value = database.get(key);
 9                 redis.set(key, value, expire_time);
10                 redis.del(key_mutex);
11             } else {
12                 // 其他线程已经在加载缓存,等待并重新获取即可
13                 sleep(50);
14                 get(key);
15             }
16         }
17         return value;
18     }

 

三、缓存雪崩:(即:缓存无数据,数据库有数据,key比较分散)

  如在高并发的情况下,缓存同一时刻失效(如缓存挂了,或者设置了相同过期时间),所有请求会读数据库,容易导致数据库负载瞬间上升,乃至崩掉。如果重启数据库,立马又会被新的请求压崩。

解决方法:

1、缓存的失效时间设置为随机值,避免同时失效。

2、redis搭建高可用,主从+哨兵,redis cluster。

3、服务限流、降级,避免数据库被瞬间压崩。

第1种只能防止因缓存同时过期导致的缓存失效,第2种可以有效避免单台缓存挂掉的情况。第3种是通过提高服务的高可用,来避免缓存失效带来的影响,是辅助措施。

 

缓存击穿和缓存雪崩区别:

  两者有点像,主要区别在于缓存击穿是查询同一条数据或热点数据查询不到,穿过了缓存。缓存雪崩是指大量数据查询不到,穿过了缓存。

 

posted @ 2021-05-18 19:29  PC君  阅读(9070)  评论(0编辑  收藏  举报