[Redis] Redis的三大缓存异常原因分析和解决方案
Redis的三大缓存异常原因分析和解决方案
缓存的三个异常分别是缓存击穿、缓存雪崩、缓存穿透。这三个问题一旦发生,会导致大量的请求积压到数据库层,并发量巨大的情况下很有可能导致数据库宕机或是故障,造成严重的生产事故。
接下来就来看看这三种缓存异常的原因分析和解决方案。
缓存击穿
缓存击穿是指针对某个热点数据的请求,无法在缓存中处理,导致大量的针对该数据的请求一下子全都发送到了后端数据库,使数据库压力激增,影响到数据库处理其他的请求。
产生原因
缓存击穿的情况,经常是发生在热点数据过期失效的情况。
如下图:
解决方案
对于缓存击穿,解决方案其实也很直接。对于访问很频繁的热点数据,就不需要设置过期时间了。这样对热点数据的访问可以直接在缓存中进行处理,Redis的数万级别的高吞吐量可以很好的应对大量的并发请求。
缓存雪崩
缓存雪崩指的是大量的应用请求无法在Redis缓存中进行处理,从而被发送到数据库层,导致数据库层的压力激增。
产生原因
产生原因一般有两种情况。
第一种情况:缓存中有大量的数据同时过期,导致请求无法得到处理。
具体来说,当数据保存在缓存中,并且设置了过期时间时,如果在某一个时刻,大量数据同时过期,此时,应用再访问这些数据的话,就会发生缓存缺失。紧接着,应用就会把请求发送给数据库,从数据库中读取数据。如果应用的并发请求量很大,那么数据库的压力也就很大,这会进一步影响到数据库的其他正常业务请求处理。
如下图:
第二中情况:Redis缓存实例发生故障,宕机了,导致大量请求积压到数据库。
一般来说,一个 Redis 实例可以支持数万级别的请求处理吞吐量,而单个数据库可能只能支持数千级别的请求处理吞吐量,它们两个的处理能力可能相差了近十倍。由于缓存雪崩,Redis 缓存失效,所以,数据库就可能要承受近十倍的请求压力,从而因为压力过大而崩溃。
解决方案
针对缓存中有大量的数据同时过期的情况,可以提供两种解决方案。
- 微调过期时间:给数据的到期时间增加一个较小的随机数,避免给大量的数据设置相同的过期的时间
- 服务降级:当发生缓存雪崩时,针对不同的数据采取不同的处理方式。
- 非核心数据:暂时停止从缓存中查询这些数据,而是直接返回预定义信息、空值或者是错误信息。
- 核心数据:缓存数据丢失时通过数据库读取。
使用服务降级的方式,只有部分的数据请求会被发送到数据库,则数据库的压力就没有那么大了。
如下图:
针对Redis缓存实例发生故障宕机的情况,同样也有两点建议。
- 在业务系统中实现服务熔断或者请求限流机制:
- 服务熔断:在发生缓存雪崩时,为了防止引发连锁的数据库雪崩,甚至是整个系统的崩溃,我们暂停业务应用对缓存系统的接口访问。
- 请求限流:在请求入口前端只允许每秒进入系统的请求数为 1000 个,再多的请求就会在入口前端被直接拒绝服务。
- 提前预防。通过主从节点的方式构建 Redis 缓存高可靠集群。如果 Redis 缓存的主节点故障宕机了,从节点还可以切换成为主节点,继续提供缓存服务,避免了由于缓存实例宕机而导致的缓存雪崩问题。
如下图:
【注:服务熔断虽然可以保证数据库的正常运行,但是暂停了整个缓存系统的访问,对业务应用的影响范围大。为了尽可能减少这种影响,可以使用请求限流的方式。】
缓存穿透
缓存穿透指的是要访问的数据既不在Redis中,也不在数据库中,导致请求访问缓存缓缺失,访问数据库而数据库也无数据。这样一来应用无法从数据库中读取写入缓存,缓存成了摆设,同时给数据库和缓存都带来巨大的压力。
如下图:
产生原因
- 业务层误操作:缓存中的数据和数据库中的数据被误删除了,所以缓存中和数据库中都没有数据。
- 恶意攻击:专门访问数据库中没有数据。
解决方案
提供三种解决方案
-
缓存空值或者缺省值。
一旦发生缓存穿透,可针对查询的数据在redis缓存中存一个空值或者缺省值,当应用发送后续请求进行查询的时候就可以从redis中读取到空值或者缺省值返回,避免大量请求数据库。
-
使用布隆过滤器快速判断数据是否存在,避免从数据库中查询数据,减轻数据库压力
通过查询布隆过滤器快速判断数据是否存在,如果不存在就不需要再去数据库中查询了。
-
在请求入口的前端进行请求检测。
缓存穿透很大一部分原因是有大量的恶意请求访问不存在的数据,所以对业务系统接收到的请求进行合法性检测,把恶意的请求直接过滤掉,不让它们访问后端缓存和数据库。
跟缓存雪崩、缓存击穿这两类问题相比,缓存穿透的影响更大一些。从预防的角度来说,我们需要避免误删除数据库和缓存中的数据;从应对角度来说,我们可以在业务系统中使用缓存空值或缺省值、使用布隆过滤器,以及进行恶意请求检测等方法。
扩展
布隆过滤器
定义
每布隆过滤器(Bloom Filter)是一个很长的二进制向量数组和一系列随机映射函数,用于检索一个元素是否在一个集合中
优缺点
优点:
- 时间复杂度低,增加和查询元素的时间复杂度为O(N)(N为hash函数个数,通常情况下比较小)
- 保密性强,因为布隆过滤器不存储元素本身。
- 存储空间小。
缺点:
- 有一定的误判率,但是可以通过调整参数来降低
- 无法获取元素本身
- 很难删除元素
工作原理
布隆过滤器的工作原理就是首先多个无偏hash函数把元素的hash值计算出来,这些hash值再对二进制数组的长度取模,得到每个hash值在数组中的对应位置,最后把对应位置的值设为1,完成标记。
如果数据不存在,也就是没有用布隆过滤器标记过,则二进制数组对应位置为零。
- 二进制数组
- hash函数计算元素的hash值,计算后的元素下标比较均匀的映射到位数组中
比如增加一个元素。
过程为:
- 通过k个无偏hash函数计算得到k个hash值
- 依次取模数组长度,得到数组索引
- 将计算得到的数组索引下标位置数据修改为1
如图:
【这样关于误判其实就很好理解了,hash函数再怎么好也无法完全避免hash冲突,也就是说有可能存在多个元素计算hash值为相同的,取模数组长度后的数组索引也是相同的,这就是误判的原因】
提供一个布隆过滤器在线计算网址:
https://krisives.github.io/bloom-calculator/
使用场景
- 解决Redis缓存穿透问题
- 做邮件的黑名单过滤
- 对爬虫网址做过滤,爬过的不在爬
- 解决新闻推荐过的不再推荐
- HBase/RocksDB/LevelDB等数据库内置布隆过滤器,用于判断数据是否存在,可以减少数据库的IO请求
Redis集成布隆过滤器
用Redis可以集成布隆过滤器,版本推荐6.x,最低4.x版本,下载安装插件后在redis.config配置文件中加入redisbloom.so文件的地址并重启。(若是redis集群则每个配置文件中都需要加入redisbloom.so文件的地址)
主要指令有:
- bf.add 添加一个元素
- bf.exists 判断一个元素是否存在
- bf.madd 添加多个元素
- bf.mexists 判断多个元素是否存在
本文来自博客园,作者:knqiufan,转载请注明原文链接:https://www.cnblogs.com/knqiufan/p/16212519.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)