zoukankan      html  css  js  c++  java
  • 缓存穿透、缓存击穿、缓存雪崩

    一、缓存架构图

     

    (1)在没有引入缓存的时候,我们请求的数据都是上数据库直接查询了。

    (2)引入缓存之后,我们在获取数据时会先去缓存看看有没有缓存数据,有直接返回,没有上数据库进行查询,然后设置到缓存中,再进行返回。

    (3)并不是所有的数据都要放到缓存中了:访问频率低的、读少写多的、一致性要求高的,这些就不要缓存了。

    二、缓存穿透、击穿、雪崩

    2.1 缓存穿透

    缓存穿透:用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

    通俗来讲:请求查询一个不存在的值缓存中没有数据,导致请求直接命中数据库,数据库中也没有数据,这就是缓存穿透。

    2.2 缓存击穿

    缓存击穿:缓存中的一个Key(比如一个促销商品),在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

    通俗的讲:请求查询一个存在的值(热点key)缓存中有数据缓存中数据的key刚好过期导致请求直接命中数据库。(热点key,缓存过期,直击数据库)

    常见于:秒杀(秒杀中的key就是热点key。)

    一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

    热点key在高并发下刚好过期,这些秒级请求直接打到数据库,如果数据库处理不过来,那就挂了。

    2.3 缓存雪崩

    我们先理解下雪崩的意思,大量雪体崩塌,这种自然想象就是雪崩。

    大量雪对应缓存中的就是大量的key,崩塌就是缓存过期失效了或者缓存层出现了错误(挂了),这就造成缓存雪崩了,直接请求到数据库了。

    缓存雪崩:缓存层出现了错误(可能是大量的key同一时间失效),不能正常工作了。于是所有的请求都会达到存储层,存储层的调用量会暴增(大量请求直接命中数据库),可能会造成存储层也会挂掉的情况。

    Ps:击穿雪崩的区别即在于击穿是对于某一特定的热点数据来说,而雪崩是全部数据

    三、缓存穿透、击穿、雪崩进阶理解

    3.1 理解一

      当“无key”的时候,也就是key不存在,这时候频繁请求,就会越过缓存,造成缓存穿透。

      当“有一key”且很“火热”的时候,也就是热点key,这时候频繁请求,碰巧缓存过期了,就会造成缓存击穿。

      当“有多key”的时候,也就是说大量的key,在同一时间失效了,欧侯,这时候就都请求到数据库了,这就会造成缓存雪崩了。

    3.2 理解二

    我们也可以这么理解,上面缓存的三种情况,就是在缓存在高并发下的并发问题。

    高并发下,不停的访问一个不存在的key,造成请求绕过了缓存系统,请求落到了数据库,就造成了缓存穿透。

    高并发下,不停的访问一个热点key,在缓存失效的时候,请求在此时落到了数据库,就造成了缓存击穿(缓存击穿,本来是有人挡着的,但是利用了缓存失效的间隙,进行了攻击)。

    高并发下,大批量缓存的key同时失效,此时所有请求落到了数据库,造成数据库压力过大,这就是缓存雪崩。

    四、缓存穿透、击穿、雪崩如何解决?

    4.1 缓存穿透如何解决?

    (1)在接口层增加校验

      比如用户鉴权校验,参数做校验,不合法的参数直接代码Return,比如:id 做基础校验,id <=0的直接return。

    (2)缓存NULL值

    当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

    但是这种方法会存在三个问题:

    1. 缓存NULL的时间太长NULL数据长时间得不到更新,会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
    2. 缓存NULL的时间太短达不到防止缓存击穿的效果
    3. 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

    (3)布隆过滤器(Bloom Filter)

      类似于哈希表的一种算法,用所有可能的查询条件生成一个bitmap,在进行数据库查询之前会使用这个bitmap进行过滤,如果不在其中则直接过滤,从而减轻数据库层面的压力。

    4.2 缓存击穿如何解决?

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

    (2)使用加互斥锁:对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询。

      public String get(key) {
            String value = redis.get(key);
            if (value == null) { //代表缓存值过期
                //假设设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
                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);
                    get(key);  //重试
                }
            } else {
                return value;      
            }
        }

    4.3 缓存雪崩如何解决?

    (1)redis高可用

      这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。

    (2)限流降级

      这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

    (3)数据预热

      数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。

    1. 在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间(缓存数据的过期时间设置随机),让缓存失效的时间点尽量均匀,防止同一时间大量数据过期现象发生。
    2. 设置热点数据永远不过期

    缓存穿透、击穿、雪崩总结

    1. 缓存穿透:查询一个不存在的值时,未命中缓存,直接落到了数据库。解决方案:接口校验、缓存NULL值、Bloom Filter。
    2. 缓存击穿:热点key,缓存过期,直击数据库。解决方案:设置永不过期、加锁互斥获取数据。
    3. 缓存雪崩:大量的缓存key在同一时间失效,导致大量请求落到数据库上。解决方案:redis高可用、限流降级、数据预热(随机过期时间、设置用不过期)。
    1. 在没有引入缓存的时候,我们请求的数据都是上数据库直接查询了。
    2. 引入缓存之后,我们在获取数据时会先去缓存看看有没有缓存数据,有直接返回,没有上数据库进行查询,然后设置到缓存中,再进行返回。
    3. 并不是所有的数据都要放到缓存中了:访问频率低的、读少写多的、一致性要求高的,这些就不要缓存了。
    1. 穿透不存在
    2. 击穿热点key
    3. 雪崩缓存挂了或者大量key失效
  • 相关阅读:
    ZOJ 3332 Strange Country II
    ZOJ 3331 Process the Tasks(双塔DP)
    ZOJ 3326 An Awful Problem(模拟)
    HDU 1796 How many integers can you find(容斥原理)
    HDU 4059 The Boss on Mars(容斥原理)
    HDU 4135 Co-prime(容斥原理)
    HDU 5677 ztr loves substring(回文串加多重背包)
    CodeForces 668B Little Artem and Dance
    CodeForces 667A Pouring Rain
    Java实现 LeetCode 764 最大加号标志(暴力递推)
  • 原文地址:https://www.cnblogs.com/mjtabu/p/12916332.html
Copyright © 2011-2022 走看看