Redis之缓存穿透、击穿、雪崩

一、缓存穿透

        缓存穿透是指在使用缓存系统时,特定的查询在缓存和数据库中都找不到结果,导致每次查询都要访问数据库,从而增加数据库的压力,降低系统的性能,若黑客利用此漏洞进行攻击可能压垮数据库。

        当一个查询请求经过缓存系统时,缓存先检查是否有缓存的结果,如果有则直接返回给客户端,如果没有则查询数据库并将结果存入缓存后返回。但是,如果查询的数据在数据库中不存在,那么每次查询都会通过缓存系统直接访问数据库,导致数据库无效查询增加,浪费了系统资源。

1.1 缓存穿透发生的条件

  • 应用服务器压力变大
  • redis 命中率降低
  • 一直查询数据库,使得数据库压力太大而压垮
  • 其实 redis 在这个过程中一直平稳运行,崩溃的是我们的数据库(如 MySQL)。

1.2 常见的缓存穿透场景

  1. 查询不存在的数据:一个用户查询一个不存在的数据,由于缓存中没有缓存该数据,会访问数据库进行查询。
  2. 恶意查询:如果攻击者故意发送大量不存在的请求,试图绕过缓存,并导致大量无效的数据库查询请求。数据库会最先崩溃。

1.3 缓存穿透带来的问题

  1. 增加数据库负载:由于缓存穿透导致大量无效的数据库查询操作,增加了数据库的负载,可能导致数据库性能下降。

  2. 击穿缓存:如果缓存中缓存了查询结果为空的键,恶意攻击者可以通过大量请求这些不存在的键,使缓存中的该键过期,从而导致后续请求都直接访问数据库,形成缓存击穿。

1.4 解决方案

  1. 空结果缓存:在缓存中存储空结果的键,可以避免缓存穿透,防止恶意攻击。

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

  3. 布隆过滤器(Bloom Filter):在查询前先通过布隆过滤器快速判断查询的数据是否存在,若不存在则不再访问缓存和数据库,减轻数据库压力。

  4. 进行实时监控:当发现 Redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。

 综上所述,缓存穿透是一种常见的缓存问题,采取适当的预防措施可以避免对数据库造成不必要的压力,并提高系统的性能和稳定性。

二、缓存击穿

        缓存击穿是指在使用缓存系统时,一个热门的、经常被访问的数据缓存过期或失效时,大量并发请求同时涌入,直接访问数据库,导致数据库负载剧增,造成系统性能下降甚至崩溃的情况。

2.1 常见的缓存击穿情况

  1. 高并发热门数据:某个数据非常热门,并且被大量并发请求频繁访问。如果该数据的缓存过期或者被意外清空,大量的请求会直接访问数据库,导致数据库压力激增。

  2. 突发请求:在某个时间点突然出现大量请求访问某个数据,而该数据的缓存恰好在此时失效,导致大量请求绕过缓存直接访问数据库。

2.2 缓存击穿会带来的问题

  1. 增加数据库负载:大量并发请求同时访问数据库,导致数据库性能下降,甚至崩溃。

  2. 响应时间延长:绕过缓存直接访问数据库,数据库响应时间增加,造成请求的响应时间延长。

2.3 解决方案

  1. 预先设置热门数据:在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长。
  2. 加锁或互斥机制:在缓存失效时,只允许一个请求访问数据库,并将结果缓存,其他请求等待并从缓存中获取数据。

  3. 热点数据永远不过期:对于热点数据,可以将其缓存时间设置为永不过期,或者设置一个合理的较长过期时间,确保不会频繁去访问数据库。

  4. 异步更新缓存:当某个热点数据的缓存过期时,可以使用异步任务来更新缓存,先返回旧的缓存结果给请求,然后在后台异步更新缓存。

  5. 限流和降级:对于突发的大量请求,可以采取限流策略,限制并发访问的请求数量,或者通过降级策略返回预设的默认值,避免数据库负载过大。

  6. 实时调整:现场监控哪些数据热门,实时调整 key 的过期时长。

  7. 前置缓存:在缓存层之前添加一个前置缓存(如CDN等),将请求分摊到多个缓存节点,减轻热点数据的单一缓存节点压力。

使用锁:
就是在缓存失效的时候(判断拿出来的值为空),不是立即去 load db。
先使用缓存工具的某些带成功操作返回值的操作(比如 Redis 的 SETNX)去 set 一个 mutex key。
当操作返回成功时,再进行 load db 的操作,并回设缓存,最后删除 mutex key;
当操作返回失败,证明有线程在 load db,当前线程睡眠一段时间再重试整个 get 缓存的方法。

三、缓存雪崩

        缓存雪崩是指在使用缓存系统时,大量缓存失效或过期,导致原本应该由缓存提供的数据,都需要从数据库中重新加载,从而引发数据库压力剧增、性能下降,甚至系统崩溃的现象。

        缓存雪崩与缓存击穿的区别在于这里针对很多 key 缓存,前者则是某一个 key 正常访问。 

3.1 常见的缓存雪崩情况

  1. 缓存批量失效:多个缓存键的过期时间或失效时间几乎同时到达,导致大量缓存同时失效。

  2. 重启或故障:缓存系统出现重启、宕机或故障,导致缓存中的所有数据一时无法访问,请求直接访问数据库。

  3. 数据库压力:当缓存失效后,大量请求同时涌入数据库,因为数据库无法承受如此大的压力而导致性能下降

3.2 缓存雪崩带来的问题

  1. 数据库压力过大:大量请求直接访问数据库,导致数据库处理能力不足,出现性能问题,甚至引发数据库崩溃。

  2. 响应时间延长:由于缓存失效,请求需要直接访问数据库,导致响应时间延长。

3.3 解决方案

  1. 构建多级缓存架构:nginx 缓存 + redis 缓存 + 其他缓存(ehcache 等)。
  2. 使用锁或队列:用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上,该方法不适用高并发情况。
  3. 设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际 key 的缓存。
  4. 将缓存失效时间分散开(设置随机过期时间):比如可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
  5. 二级缓存机制:使用多级缓存,将数据同时存储到多个缓存层,一级缓存失效时可以从二级缓存中获取数据,避免所有缓存同时失效。

  6. 缓存预热:在系统低峰期,提前加载热门的缓存数据,避免在高峰期同时加载大量缓存数据。

共同点:

  1. 都会导致大量请求直接访问数据库,增加数据库负载和降低系统性能。
  2. 都与缓存失效或过期相关,导致缓存无法提供预期的数据。

相关推荐

  1. Redis缓存穿透击穿雪崩

    2024-04-07 18:32:02       18 阅读
  2. Redis缓存穿透击穿雪崩

    2024-04-07 18:32:02       13 阅读
  3. Redis缓存穿透缓存击穿缓存雪崩、无底洞

    2024-04-07 18:32:02       13 阅读
  4. Redis缓存击穿缓存雪崩缓存穿透

    2024-04-07 18:32:02       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-07 18:32:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-07 18:32:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-07 18:32:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-07 18:32:02       20 阅读

热门阅读

  1. 在CentOS 7上安装MySQL 8.0的详细步骤讲解

    2024-04-07 18:32:02       16 阅读
  2. DM数据库状态

    2024-04-07 18:32:02       13 阅读
  3. 【故事】无人机学习之旅

    2024-04-07 18:32:02       17 阅读
  4. 客户主数据冻结

    2024-04-07 18:32:02       18 阅读
  5. MySQL中日期有关函数

    2024-04-07 18:32:02       23 阅读
  6. 54.螺旋矩阵

    2024-04-07 18:32:02       18 阅读
  7. C++ P1152 欢乐的跳

    2024-04-07 18:32:02       12 阅读
  8. LeetCode-热题100:45. 跳跃游戏 II

    2024-04-07 18:32:02       17 阅读