Redis生产问题:缓存穿透、击穿、雪崩

一、缓存穿透

简单来说就是大量请求的key既不存在于缓存中,也不存在于数据库中,结果大量请求未经缓存,直达数据库,数据库可能没抗住,就崩了。

 解决办法:

1.非法请求的限制

当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此在 API 入口处我们要判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进一步访问缓存和数据库。

2.缓存空值或者默认值

当我们线上业务发现缓存穿透的现象时,可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

3.布隆过滤器

使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。

我们可以在写入数据库数据时,使用布隆过滤器做个标记,然后在用户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,就不用通过查询数据库来判断数据是否存在。

布隆过滤器的基本步骤
  1. 初始化布隆过滤器:

    • 确定位数组的大小(m)和哈希函数的数量(k)。
    • 创建一个长度为m的位数组,并将所有位初始化为0。
  2. 添加元素:

    • 将要添加的元素输入到k个独立的哈希函数中进行哈希运算。
    • 每个哈希函数都会生成一个位数组中的位置(通常是0到m-1之间的整数)。
    • 将这些位置的位值设置为1,表示该元素存在于布隆过滤器中。
  3. 查询元素:

    • 将要查询的元素输入到相同的k个哈希函数中进行哈希运算。
    • 检查这些位置的位值,如果其中任何一个位置的位值为0,则可以确定该元素肯定不存在于布隆过滤器中。
    • 如果所有位置的位值都为1,则不能确定该元素是否真的存在于布隆过滤器中,因为可能存在哈希冲突。

举个例子,假设有一个位图数组长度为 8,哈希函数 3 个的布隆过滤器。

 

在数据库写入数据 x 后,把数据 x 标记在布隆过滤器时,数据 x 会被 3 个哈希函数分别计算出 3 个哈希值,然后在对这 3 个哈希值对 8 取模,假设取模的结果为 1、4、6,然后把位图数组的第 1、4、6 位置的值设置为 1。当应用要查询数据 x 是否数据库时,通过布隆过滤器只要查到位图数组的第 1、4、6 位置的值是否全为 1,只要有一个为 0,就认为数据 x 不在数据库中

布隆过滤器由于是基于哈希函数实现查找的,高效查找的同时存在哈希冲突的可能性,比如数据 x 和数据 y 可能都落在第 1、4、6 位置,而事实上,可能数据库中并不存在数据 y,存在误判的情况。

所以,查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据

二、缓存击穿

缓存击穿中,请求的 key 对应的是 热点数据 ,该数据 存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。这就可能会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。

 解决方法:

  1. 设置热点数据永不过期:

    对于一些热点数据,可以设置其缓存永不过期,或者过期时间设置较长,以保证即使在缓存失效时仍可从缓存中获取数据,避免直接访问数据库。
  2. 使用互斥锁/分布式锁:

    在缓存失效的时候,可以使用互斥锁或者分布式锁来保证只有一个线程去查询数据库,其他线程等待查询结果。这样可以避免大量的请求同时访问数据库,减轻数据库的负载压力。
  3. 延迟缓存更新:

    当缓存过期时,不立即更新缓存,而是等待一个较短的时间(例如几秒钟),期间的请求仍然访问旧的缓存数据。在等待时间内,后续的请求可以共享同一个缓存查询结果,从而避免了大量的并发请求直接访问数据库。
  4. 使用互斥锁/分布式锁进行缓存更新:

    当缓存过期时,使用互斥锁或者分布式锁,只允许一个线程去查询数据库并更新缓存,其他线程等待查询结果。这样可以避免缓存失效瞬间的并发访问数据库。
  5. 引入缓存预热:

    在系统启动时,提前加载热点数据到缓存中,以避免在正式请求到来时出现缓存未命中的情况。这样可以减少缓存击穿的概率。

三、缓存雪崩 

缓存中大量的缓存数据同时失效或者过期,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。

缓存雪崩和缓存击穿区别 

缓存雪崩导致的原因是缓存中的大量或者所有数据失效,缓存击穿导致的原因主要是某个热点数据不存在与缓存中(通常是因为缓存中的那份数据已经过期)。

 解决方法:

  1. 设置缓存数据的随机过期时间:

    在缓存数据的过期时间上引入随机性,使得大量缓存数据不会在同一时间过期。这样可以避免缓存数据集中在某个时间点同时失效,减轻数据库的压力。
  2. 实施缓存高可用架构:

    使用主从复制、分布式缓存等技术,将缓存服务器进行集群部署,提高缓存的可用性。当某个缓存节点失效时,其他节点可以继续提供缓存服务,避免整个系统的缓存同时失效。
  3. 设置热点数据永不过期:

    对于一些热点数据,可以设置其缓存永不过期,或者过期时间设置较长,以保证即使在缓存失效时仍可从缓存中获取数据,避免直接访问数据库。
  4. 提前进行缓存数据的加载和预热:

    在系统启动或者低峰期,提前加载和预热缓存数据,使得缓存中的数据处于一个稳定的状态。这样可以避免在高峰期同时大量缓存数据失效而导致的雪崩效应。
  5. 使用限流和降级策略:

    当缓存失效后,可以通过限制并发请求的数量,对请求进行合理的限流,避免大量的请求同时涌入数据库。同时,可以采用降级策略,如返回默认值或者错误提示,保证系统的可用性。
  6. 监控和预警机制:

    建立监控和预警系统,实时监测缓存状态、缓存命中率、缓存过期情况等指标,并及时发出预警,以便及时采取措施应对缓存雪崩问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值