一文说清Redis缓存击穿,雪崩,穿透,及解决办法

本文深入探讨了缓存雪崩、缓存穿透及缓存击穿等常见问题,提供了多种应对策略,包括分布式缓存、布隆过滤器及加锁机制,确保系统稳定运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缓存雪崩

缓存雪崩是指大量热点数据同时过期,导致请求直接落到数据库,对数据库造成巨大压力甚至宕机。

解决方案:

1.简单方案
不让缓存同时过期。可以在过期时间上加一定范围的随机数,也可以将一些几乎不改变的数据设置为永远不过期。

2.复杂方案
分布式缓存+多个数据库,使请求尽可能分布在不通的redis 和mysql数据库中,在过期时间有限制的场景,也可以使用该方案,使多个库共同分担压力。

缓存雪崩的事前事中事后的解决方案如下。

  • 事前:redis 高可用,主从+哨兵,redis cluster,避免全盘崩溃。
  • 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。
  • 事后:redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

缓存穿透

缓存穿透是指大量请求不命中缓存,直接穿透到数据库。可能是由黑客频繁请求某些不存在的id ,比如持续请求id>一千万的一系列数据,因为这些数据缓存里不存在,所以每次都会请求数据库,即产生了缓存穿透。

解决办法:

1.初级方案:
将不存在的数据也缓存起来。比如某个数据不存在,在redis中就缓存一个null,下次再请求这个数据就会命中缓存了。

2.优化方案:
方案一可以解决单个key的穿透问题,但如果黑客拿一系列不存在的key,就会在redis产生大量值为null的key ,占满内存,很快也会拖垮我redis。那么我们可以使用一个set 将存在的key都存在这个set里,取的时候先从set里查看下,如果存在再读缓存,如果不存在直接返回null。注意需要该set的预热。

3.终极方案:
方案2中用于过滤的set在数据量少的时候可以使用,如果数据量巨大,那么该set将会占用大量的内存。所以需要祭出缓存穿透的终极方案,布隆过滤器。在redis 4.0以后都支持布隆过滤器,其结构就是一个位数字,由于每个元素只占1位,所以100000个元素,也只有100000/8=12500 即越12KB内存,大大减轻了redis内存负担。
布隆过滤器的工作原理,是将key进行多次hash运算,比如存在三个哈希函数,就进行三次运算,分别得到的值为s1,s2,s3。再将位数组中对应的位置为1。
查找的时候再对key进行三次运算,对应位都位1则说明该值可能存在。
如果有一个位置不为1,则返回不存在。

注意事项1:
使用布隆过滤器要考虑到哈希碰撞的情况,也就是随着数据的增多,有可能两个不同的key三次哈希运算得到的值是一样的,所以会产生误判该值存在的情况。这个错误率,也是布隆过滤器可调节的指标之一。
所以在使用布隆过滤器时,最好通过该值不存在进行判断更为准确。

redis 布隆过滤器使用方法:

//创建一个布隆过滤器,并设置错误率为万分之一,容量100w
bf.reserve one-more-filter 0.0001 1000000
//添加key
bf.add one-more-filter fans1
//判断key是否存在
bf.exists one-more-filter fans1

注意事项2:
错误率的设置会影响内存占用,越低说明判断越准确,所需要的内存占用也就越高。

缓存击穿

缓存击穿是指在热点key失效时,同时有大量请求过来,同时透传到数据库,造成数据库压力或崩溃。

解决办法:

解决办法就是加锁,在请求数据库操作,只允许一个请求进行,其他请求等待该请求返回,再从redis中读取数据。在spring cache中这个操作非常简单,只需要在注解中加上sync=true,如@Cacheable(value = “test”, key = “#a0”, sync = true)。非springcache可以考虑使用个分布式锁,如zookeeper或redis锁用来实现此功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值