• redis缓存穿透、击穿、雪崩


    62ca9ddcea4549b0850f285851bd4c02.jpg在我们日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者是主页访问量瞬间较大的时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。

     

     

    为了克服上述的问题,项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。

     

    redis技术就是NoSQL技术中的一种,但是引入redis又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题。本文就对这三种问题进行较深入剖析。

     

    一、缓存穿透

    1.1 什么是缓存穿透

    缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中,请求都会压到数据库,从而压垮数据库。比如用户一个不存在的用户id获取用户信息

    在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义。

     

    image-20221126150803127

     

    1.2 缓存穿透解决方案

    一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

    下面有3种方法可以有效地解决缓存穿透问题

     

    对空值缓存:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。

     

    设置可访问的白名单:使用bitmaps;类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmaps里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问

     

    采用布隆过滤器:布隆过滤器(Bloom Filter)是由Howard Bloom在1970年提出的一种比较巧妙的概率型数据结构,它可以告诉你某种东西一定不存在或者可能存在。当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。 布隆过滤器相对于Set、Map 等数据结构来说,它可以更高效地插入和查询,并且占用空间更少,它也有缺点,就是判断某种东西是否存在时,可能会被误判。但是只要参数设置的合理,它的精确度也可以控制的相对精确,只会有小小的误判概率。

     

    这里重点讲一下布隆过滤器

     

    了解布隆过滤器的用途,下面有必须要把它的原理解释一下,不然有些读者还会继续蒙在鼓里。

     

    布隆过滤器是一个 bit 向量或者说 bit 数组,长这样

     

    向布隆过滤器中添加key时,会使用多个hash函数对key进行hash,算得一个整数索引值,然后对位数组进行取模运算得到一个位置,每个hash函数都会算得一个不同的位置。在把位数组的这几个位置都置为1

     

    向布隆过滤器询问key是否存在时,也会把hash的几个位置都算出来,看看位数组中这几个位置是否都为1,只要有一个位为0,那么说明布隆过滤器中这个key不存在。如果这几个位置都是1,并不能说明这个key就一定存在,只是极有可能存在,因为这些位被置为1可能是因为其他的key存在所致。如果这个位数组比较稀疏,判断正确的概率就会很大,如果这个位数组比较拥挤,判断正确的概率就会降低。

     

    二、缓存击穿

    1.1 什么是缓存击穿

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

    image-20221126151619669

     

    比如前段时间的吴签事件,如果没有把这个词作为热点词存储到缓存中或者缓存时间到期,那么用户访问这个词时,就会通过缓存,直接访问数据库,引起数据库压力瞬间增大。

     

    它和缓存穿透的区别在于:缓存击穿是指缓存中没有但数据库中有的数据,由于并发用户特别多,同时读缓存没读到数据,同时数据库取数据引起数据库压力瞬间增大,造成过大压力。缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起的数据特别大而不存在的数据

     

    1.2 缓存击穿解决方案

    key可能会在某些时间点被高并发访问,是一种非常热点的数据,这个时候,需要考虑一个问题,缓存被击穿的问题

    下面介绍2种方法可以有效地解决缓存击穿问题

     

    预先设置热门数据:在redis高峰访问前,把一些热门数据提前存入redis中,加大这些热门数据key的时长实时调整 现场监控哪些数据是热门数据,实时调整key的过期时长

     

    使用分布式锁: 就是在缓存失效的时候(判断拿出来的值为空),不是立即去查数据库,先使用缓存工具的某些带成功操作返回值的操作。比如redis的setnx去set一个mutex key,当操作返回成功时(分布式锁),在查数据库,并回设缓存,最后删除mutex key

    当操作返回失败,证明有线程在查询数据库,当前线程睡眠一段时间在重s试整个get缓存的方法

     

    三、缓存雪崩

     

    3.1 什么是缓存雪崩

    缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

    常见缓存雪崩出现原因:1、redis服务器挂掉了。2、对缓存数据设置了相同的过期时间,导致某时间段内缓存集中失效。

     

    image-20221126161038150

     

    3.2 缓存雪崩解决方案

    缓存雪崩解对底层系统的冲击是非常大的:

    解决方案:

     

    构建多级缓存架构:nginx缓存+redis缓存+其他缓存(ehcache等)

     

    使用锁或队列:使用锁或在队列的方式来保证不会有大量的线程对数据库进行读写,从而避免失效时大量的并发请求到底层存储系统上,不适用高并发情况

     

    设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存

     

    将缓存失效时间分散开:设置缓存过期时间时加上一个随机值,避免缓存在同一时间过期

  • 相关阅读:
    Flink热门商品统计
    分析 20 个 veToken 生态系统协议 这种代币模型为何受欢迎?
    【Java项目-飞翔的小鸟】附源码
    云服务部署:AWS、Azure和GCP比较
    K8S中的ingress
    【RocketMQ】消息的存储
    一文了解人工智能AI、大模型、AI大模型、ChatGPT、GPT-4、OpenAI、Claude 3...
    查询并关闭被占用的端口
    线性dp,优化,库特鸽鸽的时间分配
    Python学习 第四章 面向对象设计
  • 原文地址:https://blog.csdn.net/weixin_57763462/article/details/134542173