Redis之缓存预热、缓存雪崩、缓存击穿和缓存穿透以及布隆过滤器

一、缓存预热

缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

二、缓存雪崩

指的是在短时间内,大量的键过期导致请求直接打到数据库,或者是Redis宕机,导致请求直接打到数据库,而数据库无法处理如此大量的请求,导致数据库宕机,进而造成整个系统或者服务的不可用。牵一发而动全身。

解决方案:

  1. Redis缓存集群实现高可用(合理设置过期时间或者延时,采用哨兵集群等)
  2. 采用多级缓存策略,例如 Nginx缓存+Redis缓存+ehcache缓存
  3. 采用Hystrix或者阿里sentinel进行服务限流限流或者降级
  4. 监控Redis各项指标,即使灾难预警
  5. 采用AOF/ RDB持久化,尽快恢复Redis集群

三、缓存击穿

缓存击穿就是单个热点key突然失效或者过期,导致大量的请求未命中Redis之后打在数据库上,导致数据库压力剧增

解决方案

  • 对于热点key加长过期时间,或者干脆不设置过期时间
  • 二级缓存设置不同的失效时间,保证不会同时失效
  • 如果缓存中没有该key则加锁,保证只会有一个线程打到数据库进行查询(效率较低)

四、缓存穿透

缓存穿透指的是⼤量请求的 key 根本不存在于缓存中,导致请求直接到了数据库上,根本
没有经过缓存这⼀层,并且在数据库中也没有该跳数据,导致也没有继续回写到缓存中,导致大量请求直接打到数据库层面

解决方案:

  • 缓存空对象或者缺省值
    • 如果在数据库也无法查询,同样回写到缓存中null值,第二次请求就不会落到数据库中
    • 如果黑客恶意攻击每次采取不同的ID那么缓存将越写越多,所以要设置过期时间,并且大量请求还是直接打中了数据库所以该方案有缺陷
  • 使用布隆过滤器,下一章详细讲解

五、布隆过滤器

想要尽量避免缓存穿透,一个办法就是对数据进行预校验,在对Redis和数据库进行操作前,先检查数据是否存在,如果不存在就直接返回。如果我们想要查询一个元素是否存在,要保证查询效率,可以选择HashSet,但是如果有10亿个数据,都用HashSet进行存储,内存肯定是无法容纳的。这时就需要布隆过滤器了

布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(bit数组)一系列随机映射函数(hash)。布隆过滤器可以用于检索一个元素是否在一个集合中

特点:

  • 高效地插入和查询,占用空间少,返回的结果是不确定性的。
  • 一个元素如果判断结果为存在的时候元素不一定存在,但是判断结果为不存在的时候则一定不存在。
  • 布隆过滤器可以添加元素,但是不能删除元素。因为删掉元素会导致误判率增加。
  • 误判只会发生在过滤器没有添加过的元素,对于添加过的元素不会发生误判。

1. 原理实现

① 初始化

布隆过滤器 本质上 是由长度为 m 的位向量或位列表(仅包含 0 或 1 位值的列表)组成,最初所有的值均设置为 0

在这里插入图片描述
② 添加

当我们向布隆过滤器中添加数据时,为了尽量地址不冲突,会使用多个 hash 函数对 key 进行运算,算得一个下标索引值,然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。

例如,我们添加一个字符串wmyskxz

在这里插入图片描述
③ 查询

向布隆过滤器查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算,查看对应的位置是否都为 1

只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在

如果这几个位置全都是 1,那么说明极有可能存在;

为什么说极有可能呢?

因为这些位置的 1 可能是因为其他的 key 存在导致的,也就是hash冲突

就比如我们在 add 了字符串wmyskxz数据之后,很明显1/3/5 这几个位置的 1 ,如上图,是因为第一次添加的 wmyskxz 而导致的;此时我们查询一个没添加过的不存在的字符串inexistent-key,它有可能计算后坑位也是1/3/5 ,这时候经过hash函数计算以及查询发现1 /3 / 5 的位置都是1,所以布隆过滤器认为该数据是存在的,就发生了误判

在这里插入图片描述
为什么key不能删除呢?

因为该key经过运算放入bit数组中的值,并不一定是你产生的,有可能其他数值也共用着这个数位,如果你删除了该位置,别的key进行查询时可能导致查询失败

2. Google工具包Guava实现布隆过滤器

  • 首先将maven中导入相关依赖(其他一些SpringBoot整合redis依赖就不赘述了)
        <!--Google 开源的 Guava 中自带的布隆过滤器-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>
  • 模拟秒杀场景获取商品详情页面的单机版Guava实现布隆过滤器

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.Data;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.
缓存穿透缓存击穿缓存雪崩是常见的缓存相关问题,它们可能导致缓存失效或性能下降。下面是对它们的原因和解决方法的简要说明: 1. 缓存穿透缓存穿透是指请求的数据在缓存数据库中都不存在,导致每次请求都要访问数据库,增加了数据库负载。主要原因是恶意攻击或错误的查询。 解决方法: - 使用布隆过滤器:在查询前使用布隆过滤器检查请求是否有效,如果无效则直接返回,避免对数据库的查询。 - 设置空对象缓存:将数据库中不存在的值也缓存起来,可以防止频繁查询。 2. 缓存击穿缓存击穿是指一个热点数据失效,导致大量请求同时访问数据库,造成数据库压力过大。主要原因是热点数据过期或删除。 解决方法: - 设置热点数据永不过期:针对热点数据设置永不过期,确保即使失效也能从缓存中获取,并在后台异步更新缓存。 - 互斥锁(Mutex):当缓存失效时,只允许一个线程访问数据库并更新缓存,其他线程等待获取缓存数据。 3. 缓存雪崩缓存雪崩是指缓存中大量的数据同时失效,导致所有请求都要访问数据库,造成数据库负载过大。主要原因是缓存中的数据同时过期。 解决方法: - 设置随机过期时间:为缓存数据设置随机的过期时间,避免大量数据同时失效。 - 使用分布式缓存:将缓存分布在不同的节点上,提高系统的可用性和容错能力。 - 数据预热:提前加载热点数据到缓存中,避免在高并发时突然访问数据库。 以上是对缓存穿透缓存击穿缓存雪崩问题的原因和解决方法的简要介绍,实际应用中可能还需要结合具体场景进行调整和优化。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值