Redis之缓存穿透、缓存击穿、缓存雪崩及删除淘汰策略

缓存穿透

什么是缓存穿透

正常情况下,查询的数据都存在,如果请求一个不存在的数据,也就是缓存和数据库都查不到这个数据,每次都会去数据库查询,这种查询不存在数据的现象我们称为缓存穿透

穿透带来的问题

如果每次都拿一个不存在的id去查询数据库,可能会导致你的数据库压力增大

解决办法

  • 缓存空值:之所以发生穿透,是因为缓存中没有存储这些数据的key,从而每次都查询数据库我们可以为这些key在缓存中设置对应的值为null,后面查询这个key的时候就不用查询数据库了当然为了健壮性,我们要对这些key设置过期时间,以防止真的有数据
  • BloomFilter(布隆过滤器): BloomFilter 类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中,我们把有数据的key都放到BloomFilter中,每次查询的时候都先去BloomFilter判断,如果没有就直接返回null,注意BloomFilter没有删除操作,对于删除的key,查询就会经过BloomFilter然后查询缓存再查询数据库,所以BloomFilter可以结合缓存空值用,对于删除的key,可以在缓存中缓存null

缓存击穿

什么是缓存击穿

在高并发的情况下,大量的请求同时查询同一个key时,此时这个key正好失效了,就会导致同一时间,这些请求都会去查询数据库,这样的现象我们称为缓存击穿

击穿带来的问题

会造成某一时刻数据库请求量过大

解决办法

采用分布式锁,只有拿到锁的第一个线程去请求数据库,然后插入缓存,当然每次拿到锁的时候都要去查询一下缓存有没有

缓存雪崩

什么是缓存雪崩

当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了

解决办法

  1. 采用集群,降低服务宕机的概率
  2. ehcache本地缓存 + Hystrix限流&降级,ehcache 本地缓存的目的也是考虑在 Redis Cluster 完全不可用的时候,ehcache 本地缓存还能够支撑一阵,使用 Hystrix进行限流 & 降级 ,比如一秒来了5000个请求,我们可以设置假设只能有一秒 2000个请求能通过这个组件,那么其他剩余的 3000 请求就会走限流逻辑

解决热点数据集中失效问题

我们在设置缓存的时候,一般会给缓存设置一个失效时间,过了这个时间,缓存就失效了。对于一些热点的数据来说,当缓存失效以后会存在大量的请求过来,然后打到数据库去,从而可能导致数据库崩溃的情况

解决办法
1.设置不同的失效时间
2.采用缓存击穿的解决办法,加锁
3.永不失效,就是采用定时任务对快要失效的缓存进行更新缓存和失效时间

Redis中的数据特征

redis是一种内存级数据库,所有的数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态

  • xx : 距离过期还剩下多少秒
  • -1: 永久有效的数据
  • -2: 已经过期的数据 或被删除的数据 或未定义的数据

删除策略就是针对已过期数据的处理策略,已过期的数据是真的就立即删除了吗?其实也不是,我们会有多种删除策略,是分情况的,在不同的场景下使用不同的删除方式会有不同效果

时效性数据的存储结构

在redsi中,如果给数据设置了过期时间,那麽数据的存储结构如下图所示

在这里插入图片描述
过期数据是一块独立的存储空间,Hash结构,field是内存地址,value是过期时间,保存了所有key的过期描述,在最终进行过期处理的时候,对该空间的数据进行检测, 当时间到期之后通过field找到内存该地址处的数据,然后进行相关操作。

1.2 数据删除策略

数据删除策略的目的是什么?

在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能下降,甚至引发服务器宕机或内存泄漏。

针对过期数据要进行删除的时候都有哪些删除策略呢?

  • 定时删除
  • 惰性删除
  • 定期删除

定时删除:创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作

优点: 节约内存,到时就删除,快速释放掉不必要的内存占用

缺点: CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响 redis服务器响应时间和指令吞吐量

总结:用处理器性能换取存储空间(拿时间换空间)

在这里插入图片描述

惰性删除: 数据到达过期时间,不做处理。等下次访问该数据时,我们需要判断:

  • 如果未过期,返回数据
  • 发现已过期,删除,返回不存在

优点: 节约CPU性能,发现必须删除的时候才删除
缺点: 内存压力很大,出现长期占用内存的数据
总结: 用存储空间换取处理器性能(拿空间换时间)

在这里插入图片描述

定期删除:
定时删除和惰性删除这两种方案都是走的极端,那有没有折中方案?

来说下redis的定期删除方案:

  • Redis启动服务器初始化时,读取配置server.hz的值,默认为10
  • 每秒钟执行server.hz次serverCron()--(定时轮询)------>databasesCron()---(轮询访问当前redis中的所有库)>---------->activeExpireCycle()
  • activeExpireCycle()对每个expires[*]逐一进行检测,每次执行耗时:250ms/server.hz
  • 对某个expires[*]检测时,随机挑选W个key检测

具体流程见下图:

在这里插入图片描述
总的来说:定期删除就是周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度

  • 特点1:CPU性能占用设置有峰值,检测频度可自定义设置
  • 特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
  • 总结:周期性抽查存储空间(随机抽查,重点抽查

删除策略对比

1:定时删除:

节约内存,无占用,
不分时段占用CPU资源,频度高,
拿时间换空间

2:惰性删除:

内存占用严重
延时执行,CPU利用率高
拿空间换时间

3:定期删除:

内存定期随机清理
每秒花费固定的CPU资源维护内存
随机抽查,重点抽查

数据淘汰策略(逐出算法)

淘汰策略概述
什么叫数据淘汰策略?什么样的应用场景需要用到数据淘汰策略?

当新数据进入redis时,如果内存不足怎么办?在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新 加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。

注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕, 如不能达到内存清理的要求,将出现错误信息如下

(error) OOM command not allowed when used memory >'maxmemory'

策略配置

影响数据淘汰的相关配置如下:

在这里插入图片描述

那数据删除的策略policy到底有几种呢?一共是3类8种

第一类:检测易失数据(可能会过期的数据集server.db[i].expires )

volatile-lru:挑选最近最少使用的数据淘汰,可以理解成最近最久未使用
volatile-lfu:挑选最近使用次数最少的数据淘汰
volatile-ttl:挑选将要过期的数据淘汰
volatile-random:任意选择数据淘汰

结合下图进行理解:

在这里插入图片描述

第二类:检测全库数据(所有数据集server.db[i].dict )

allkeys-lru:挑选最近最少使用的数据淘汰
allkeLyRs-lfu::挑选最近使用次数最少的数据淘汰
allkeys-random:任意选择数据淘汰,相当于随机

第三类:放弃数据驱逐

no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发OOM(Out Of Memory)

注意:上面说了折磨多废话,那麽这些策略是在哪里配置呢?配置到哪个属性上?怎么配置?

这里只需要进入到redis.conf文件中去进行配置就可以了,具体配置如下:

maxmemory-policy volatile-lru

注意: 如果是你自己想要测试一下一上这些数据删除策略,前提是你的redis中有着海量数据,需要通过大量数据去冲击内存才能达到你想要看到的效果

数据淘汰策略配置依据
使用INFO命令输出监控信息,查询缓存 hit 和 miss 的次数,根据业务需求调优Redis配置

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值