首页 > 数据库 >Redis缓存穿透、击穿、雪崩、概念及解决办法

Redis缓存穿透、击穿、雪崩、概念及解决办法

时间:2022-10-17 09:34:22浏览次数:52  
标签:解决办法 存储 缓存 过期 Redis 穿透 线程 key

一、缓存穿透

1、缓存穿透理解

  缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义。(对于系统A,假设一秒 5000 个请求,结果其中 4000 个请求是黑客发出的恶意攻击。黑客发出的那 4000 个攻击,缓存中查不到,每次你去数据库里查,也查不到。)

缓存穿透问题可能会使后端存储负载加大,由于很多后端持久层不具备高并发性,甚至可能造成后端存储宕机。通常可以在程序中统计总调用数、缓存层命中数、如果同一个Key的缓存命中率很低,可能就是出现了缓存穿透问题。
  造成缓存穿透的基本原因有两个。第一,自身业务代码或者数据出现问题(例如:set 和 get 的key不一致),第二,一些恶意攻击、爬虫等造成大量空命中(爬取线上商城商品数据,超大循环递增商品的ID)

2、解决方案

2.1 缓存空对象

  缓存空对象:是指在持久层没有命中的情况下,对key进行set (key,null)

  缓存空对象会有两个问题:
   第一,value为null 不代表不占用内存空间,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间,比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。
   第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

2.2 布隆过滤器拦截

   在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截,当收到一个对key请求时先用布隆过滤器验证是key否存在,如果存在在进入缓存层、存储层。可以采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间。这种方法适用于数据命中不高、数据相对固定、实时性低的应用场景,代码维护较为复杂,但是缓存空间占用少。

   布隆过滤器实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。

它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

   布隆过滤器拦截的算法描述:

   初始状态时,BloomFilter是一个长度为m的位数组,每一位都置为0。

   添加元素x时,x使用k个hash函数得到k个hash值,对m取余,对应的bit位设置为1。

   判断y是否属于这个集合,对y使用k个哈希函数得到k个哈希值,对m取余,所有对应的位置都是1,则认为y属于该集合(哈希冲突,可能存在误判),否则就认为y不属于该集合。可以通过增加哈希函数和增加二进制位数组的长度来降低错报率。

二、缓存击穿

1、缓存击穿的理解

   缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

2、解决方案

2.1 分布式互斥锁

   只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可。set(key,value,timeout)

2. 永不过期

   从缓存层面来看,确实没有设置过期时间,所以不会出现热点key过期后产生的问题,也就是“物理”不过期。

   从功能层面来看,为每个value设置一个逻辑过期时间,当发现超过逻辑过期时间后,会使用单独的线程去更新缓

3、两种方案对比:

  分布式互斥锁:这种方案思路比较简单,但是存在一定的隐患,如果在查询数据库 + 和 重建缓存(key失效后进行了大量的计算)时间过长,也可能会存在死锁和线程池阻塞的风险,高并发情景下吞吐量会大大降低!但是这种方法能够较好地降低后端存储负载,并在一致性上做得比较好。

  永远不过期:这种方案由于没有设置真正的过期时间,实际上已经不存在热点key产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。

三、缓存雪崩

1、概念理解

  如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

  这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。

2、解决方案

2.1 缓存层高可用:

   可以把缓存层设计成高可用的,即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务。利用sentinel或cluster实现。

2.2 做二级缓存,或者双缓存策略:

   采用多级缓存,本地进程作为一级缓存,redis作为二级缓存,不同级别的缓存设置的超时时间不同,即使某级缓存过期了,也有其他级别缓存兜底

2.3 数据预热:

   可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀

2.4 加锁排队. 限流-- 限流算法. 1.计数 2.滑动窗口 3. 令牌桶Token Bucket 4.漏桶 leaky bucket [1]

   在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
   SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

标签:解决办法,存储,缓存,过期,Redis,穿透,线程,key
From: https://www.cnblogs.com/peteremperor/p/16797989.html

相关文章

  • docker安装tomcat、mysql、redis
    一、tomcat1.下载tomcat8dockerpulltomcat:8.5.612.启动容器(-d后台启动)dockerrun-d-p8080:8080tomcat:8.5.61 3.访问首页http://ip:8080/访问不到......
  • 端口占用的解决办法
    Win+R调出运行框,输入cmd对于Java线程输入jps回车查看线程的pid(这里pid以15566为例)关闭线程,输入taskkill/f/pid15566对于指定端口(这里端口以8080为例)查找线程pi......
  • Docker基础知识 (16) - 部署 Redis 集群
    Redis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value的NoSQL数据库,并提供多种语言的API。大型网站为了提高站点响应速度,使用......
  • mysql 数据从5.6版迁移到5.7以后版的数据(包括8.0) 提示sql_mode=only_full_group_by
    SQLSTATE[42000]:Syntaxerrororaccessviolation:1055Expression#1ofSELECTlistisnotinGROUPBYclauseandcontainsnonaggregatedcolumn'sid.xid'which......
  • 基于redis的查询业务缓存实现
    添加缓存业务流程及代码实现业务流程说明:1、先从redis中进行查询,redis中如果有对应的数据则直接返回;如果没有再进入数据库查询2、从数据库查询到的数据判断是否为空......
  • 数据库学习笔记04- redis
    5,Redis基础redis--KV数据库--内存--单线程+异步i/o(多路io复用)计算密集型应用:多进程+多进程IO密集型应用:单线程+异步IO(协程)2008年--redis--》REmote......
  • Redis学习笔记
    基础篇-02.初识Redis-认识NoSQL_哔哩哔哩_bilibili,参考黑马程序员出品的Redis教程,感谢黑马!基础篇一、Redis入门1.认识NoSQL1.1 什么是NoSQLNoSQL最常见的解释是"n......
  • Centos7部署redis三节点哨兵集群,添加布隆过滤器
    目录Centos7部署redis三节点哨兵集群,添加布隆过滤器一、环境准备1.1、服务器准备1.2、依赖安装二、部署redis2.1、安装redis2.2、修改配置文件2.3、加入systemctl管理三、......
  • Redis数据结构之字符串
    目录Redis数据结构之字符串添加获取修改删除判断一个key是否存在查看过期时间设置过期时间合并set和ex合并set和px判断一个key是否存在,存在则忽略,不存在则创建合并set和nx......
  • Redis数据结构之列表
    目录Redis数据结构之列表查看命令帮助创建列表从左边插入元素从右边插入数据若list存在,则从左边依次追加元素,不存在则忽略若list存在,则从右边依次追加元素,不存在则忽略从li......