• 什么是缓存雪崩,缓存穿透,缓存预热,缓存更新,缓存降级?


    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/LuQiaoYa/article/details/89243231
    什么是缓存雪崩,缓存穿透,缓存预热,缓存更新,缓存降级?
    一、缓存雪崩:
    二、缓存穿透
    三、缓存预热
    四、缓存更新
    五、缓存降级
    一、缓存雪崩:
    由于原有缓存失效,新缓存未到期间(例如我们设置缓存采用了一样的过期时间,在同一时刻造成了所有的缓存失效),所有原本应该去访问缓存的请求都去查询数据库,
    对数据库CPU和内存造成了巨大的压力,严重的会造成数据库宕机。

    缓存雪崩的解决方案:
    (1)如果并发量不是特别多的话,使用最多的方案是加锁排队。

    public void getAllList(){
    int cacheTime = 30;
    String cacheKey = "list_key";
    String lockKey = cacheKey;

    String value = CacheHelper.get(cacheKey);
    if(value != null){
    // 如果缓存有值,就直接取出来即可
    return value;
    }else{
    synchronized(lockKey){
    value = CacheHelper.get(cacheKey);
    if(value != null){
    return value;
    }else{
    // 这里一般是SQL查询语句
    value = GetListFromDB();
    // 把查询结果放入缓存
    CacheHelper.Add(cacheKey,value,cacheTime)
    }
    }
    return value ;
    }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    (2)给每一个缓存增加相应的缓存标记,记录缓存是否有效,如果缓存标记失效,则更新数据缓存,伪代码如下:

    public void getAllListNew(){
    int cacheTime = 30;
    String cacheKey = "list_key";
    // 缓存标记
    String signKey = cacheKey + "_sign";

    String sign = CacheHelper.get(signKey);
    // 获取缓存值
    String cacheValue = CacheHelper.get(cacheKey);
    if(sign != null){
    //没有过期
    return cacheValue;
    }else{
    CacheHelper.Add(signKey,"1",cacheTime);
    ThreadPool.QueueUserWorkItem((args) ->{
    // 这里一般是SQL查询语句
    cacheValue = GetListFromDB();
    CacheHelper.Add(cacheKey,cacheValue,cacheTime*2);
    })
    return cacheValue;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    缓存标记:记录缓存数据是否过期,如果过期,则会通知另外的线程在后台去更新实际key的值。

    缓存数据:缓存数据的过期时间比缓存标记的时间延长一倍,如果,缓存标记过期时间是30分钟,缓存数据的过期时间是60分钟,这样当缓存标记过期后,还能把缓存中放的旧数据返回给调用端,直到另外的线程再后台更新完成后才会返回新缓存。

    二、缓存穿透
    缓存穿透是指用户在数据库查询查不到,在缓存中自然也不会有,这样就导致每次用户查询的时候在缓存查不到,在数据库也查不到,相当于进行了两次无用查询。

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

    布隆过滤器:
    布隆过滤器相当于一个不怎么精确的set结构,布隆过滤器有两个基本指令,bf.add添加元素,bg.exits查询元素是否存在。要想一次添加多个元素,用bf.madd指令。
    要一次查找是否存在多个元素,用bf.mexits指令。

    布隆过滤器的原理如图:

    每个布隆过滤器对应到Redis的数据结构里面就是一个大型的位数组和几个不一样的无偏hash函数,所谓无偏就是能把hash值算的比较均匀。

    向布隆过滤器中添加key值时,会使用多个hash函数对key值进行hash算法取得一个哈希值,然后对数组长度进行取模运算得到一个下标位置,每个hash函数都会得到一个不同的位置,最后得到多个位置,再把位数组的这几个位置都置为1就完成了add操作。
    向布隆过滤器中查询某个key值时,也跟add操作一样,算出来hash的几个位置,看看这几个位置是否都为1,有一个为0就说明布隆过滤器中该值不存在。如果这几个位置都是1,
    也不一定说明这个key存在,也有可能是别的key值存在导致。

    Redis中使用布隆过滤器:
    布隆过滤器可能存在误判的情况,Redis中有两个值可以决定布隆过滤器的准确率。

    error_rate:允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间就越大。
    initial_size:布隆过滤器可以存储的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降。
    Redis中有一个命令可以来设置这两个值:

    bf.reserve urls 0.01 100
    1
    三个参数的含义:

    第一个是过滤器的名字
    第二个是error_rate的值
    第三个是initial_size的值
    使用这个命令要注意,执行这个命令之前这个过滤器应该是不存在的,如果存在的话会报错。
    (2)如果一个查询的数据为空,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。这样下一次访问缓存就有值了,而不会继续访问数据库。

    三、缓存预热
    缓存预热就是系统上线后,提前将相关的缓存数据直接加载到缓存系统中,避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。
    解决方案:
    (1)直接写个缓存页面,上线时手工操作下
    (2)数据量不大,可以在项目启动的时候自动加载
    (3)定时刷新缓存

    四、缓存更新
    除了缓存自带的缓存失效策略之外,我们还可以进行自定义的缓存淘汰策略,常见的策略有两种:
    (1)定期去清理过期的缓存
    (2)当有用户请求过来时,再判断这个请求用到的key是否过期,过期的话就去获取新数据并更新缓存。

    五、缓存降级
    当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。
    系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
    ————————————————
    版权声明:本文为CSDN博主「LuQiaoYa」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/LuQiaoYa/article/details/89243231

  • 相关阅读:
    zabbix配合脚本监控Kafka
    用strings命令查看kafka-log内容 过滤二进制编码
    docker容器中搭建kafka集群环境
    Elasticsearch究竟要设置多少分片数?
    elasticsearch 基础知识汇总
    ES磁盘分配不均问题
    elasticsearch-5.1.1使用snapshot接口备份索引
    filebeat.yml(中文配置详解)
    elasticsearch分词器Jcseg安装手册
    开启了1000个线程并发去查询elasticsearch把es搞挂了
  • 原文地址:https://www.cnblogs.com/wangyu19900123/p/11772578.html
Copyright © 2020-2023  润新知