Loading

[Redis]缓存穿透/缓存击穿/缓存雪崩

缓存穿透

用户访问一些不存在的数据,redis没有,于是去mysql查询也没有,这样就发生了两次无效的查询。

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,缓存永远不会生效。这样,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决方案

  • 布隆过滤器

设置布隆过滤器,布隆过滤器实际上就是一个数组加上几个哈希函数。如果布隆过滤器告诉我们这个数据不存在那就一定不存在,如果他说存在,那也不一定存在。原理是,使用多个哈希函数,把一个key值使用多个哈希函数进行运算,把相应的位置设置为1。当我们想要请求某个数据的时候,先用这几个哈希函数映射到数组的几个位置,如果这几个位置都是1,那就是存在,否则就不存在。

使用多个哈希函数是为了避免哈希冲突,从而减少误判,哈希冲突会导致,例如A和B使用同一个哈希函数产生了哈希冲突,先把A放进缓存,然后我们想要获取B的时候发现相应位置上的标志位已经被设置了,那我们以为这个数据是存在的,但实际上这个位置是因为哈希冲突被另一个数据标志的,增加哈希函数可以降低哈希冲突的概率。

  • 对空值进行缓存

即使一个查询返回的数据为空,仍然把这个空结果(null)进行缓存,同时还可以对空结果设置较短的过期时间。这种方法实现简单,维护方便,但是会额外的内存消耗。

  • 采用布隆过滤器

(布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

  • 进行实时监控

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

  • 增强 id 的复杂度,避免被猜测 id 规律
  • 做好数据的基础格式校验
  • 加强用户权限校验

缓存击穿

redis删掉了热点数据,导致大量请求发送到mysql。

解决方案

  • 互斥锁

这种情况下,线程的逻辑应该是这样的,

首先去查缓存,

  • 如果缓存里没有,尝试去设置一个分布式锁(这里实际上就是在redis中set一个键值对set ex nx),谁先设置成功了谁就获得了这个锁,

    • 获得锁的线程去查询数据库,
      • 如果查到了把数据写回缓存,
      • 如果发现没有,也要把数据写回缓存,只是要把值设置成Null,让其他线程知道数据库里没有这个数据,
    • 其他被互斥锁阻塞的线程的操作应该是这样的,
    • 尝试获取锁,但是这个操作是有过期时间的,超过一定时间还没有获取到锁,就再次去查询缓存,看看缓存里是不是有数据了,有数据也分两种情况,一种是真的数据,一种是值为null的数据,不管哪种,线程都会结束循环,但是如果查询缓存的时候发现还是没有这个数据,那就继续尝试获取锁
  • 如果缓存里有,直接返回

  • 逻辑过期

  • 热点数据永不过期

缓存雪崩

redis同时删掉了一批热点数据,导致大量请求发送到mysql。

缓存雪崩是指在同一时段大量的缓存 key 同时失效,或者 Redis 服务宕机,导致大量请求到达数据库,带来巨大压力。

解决方案

  • 给不同的 Key 的 TTL 添加随机值,失效时间设置随机
  • 设置集群
  • 在缓存失效的时候,通过加锁的方式只允许一个请求重新加载缓存数据,其他请求等待缓存加载完成。这样可以避免大量的请求同时访问数据库。
  • 利用 Redis 集群提高服务的可用性
  • 给缓存业务添加降级限流策略
  • 给业务添加多级缓存
posted @   Duancf  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示