一、Redis过期删除策略:

redis出于性能上的考虑,无法做到对每一个过期的key进行即时的过期监听和删除。但是redis提供了其它三种方法来清理过期key:

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

1、惰性删除(被动清理)

  • 策略:不主动删除过期键,每次从数据库访问 key 时,都检测 key 是否过期,如果过期则删除该 key。
  • 优点:每次访问时才会检查key是否过期,所以占用系统资源较少,对CPU消耗最少。
  • 缺点:如果某个已过期的key一直未被访问,那么会一直占用内存,浪费内存空间,对内存不友好。

2、定时删除(主动清理)

  • 策略:在设置 key 的过期时间时,同时创建一个定时事件,当时间到达时,由事件处理器自动执行 key 的删除操作,类似于epoll中针对事件注册的回调函数。
  • 优点:保证过期key会尽快被删除,尽快释放内存,对内存友好。
  • 缺点:在过期key较多时,删除过期key的操作会占用较多的CPU资源。在内存资源不紧张但CPU资源紧张的情况下,将CPU资源用于删除和当前无关的过期key上,会对服务器响应时间和Redis吞吐量造成影响,对CPU不友好。

3、定期删除(内存不足时触发主动清理)

  • 策略:每隔一段时间「随机」从数据库中取出 一定数量的 key 进行检查,并删除其中的过期key。
  • 优点:通过限制删除操作执行的时间和频率,来减少删除操作对CPU的影响,同时也能删除一部分过期数据,减少了过期key对空间的无效占用。
  • 缺点
  • 内存清理 效果没有“定时删除”效果好,同时没有“惰性删除”占用的 系统资源 少。
  • 不好确定操作执行的时长(可配置,默认10次/s)和频率(20,不可配置),如果执行太频繁,定期删除策略会变得和定时删除策略一样,对CPU不友好;如果执行太少,那又和惰性删除一样了,过期 key 占用的内存不会及时得到释放。算是对惰性删除和定时删除两种方式的一种折中~

Redis 的定期删除的流程:

  1. 从过期字典中随机抽取 20 个 key;
  2. 检查这 20 个 key 是否过期,并删除已过期的 key;
  3. 如果本轮检查的已过期 key 的数量,超过 5 个(20/4),也就是「已过期 key 的数量」占比「随机抽取 key 的数量」大于 25%,则继续重复步骤 1;如果已过期的 key 比例小于 25%,则停止继续删除过期 key,然后等待下一轮再检查。
    可以看到,定期删除是一个循环的流程。
    那 Redis 为了保证定期删除不会出现循环过度,导致线程卡死现象,为此增加了定期删除循环流程的时间上限,默认不会超过 25ms

补充面试相关问题:

Redis瞬间有大量key失效,为什么会影响别的key的读取性能?(这里需从底层原理进行分析)

因为 Redis 定期删除的定时任务,是在Redis主线程中执行的。也就是说如果在执行定期删除的过程中,出现了需要大量删除过期key的情况,那么在业务访问时,必须等这个过期任务执行结束,才可以处理业务请求。此时就会出现,业务访问延时增大的问题,最大延迟为25毫秒。

redis 删除策略 rediskey过期删除策略_redis

Redis过期删除策略是什么?

前面的三种过期删除策略,每一种都有优缺点,仅使用某一个策略都不能满足实际需求。
所以, Redis 选择「惰性删除+定期删除」这两种策略配和使用,以求在 合理使用CPU资源避免内存浪费 之间取得平衡。

二、Redis内存淘汰策略:

常见的内存淘汰策略有:

  • noeviction(Redis3.0后,默认内存淘汰策略):当运行内存超过最大设置内存时,不淘汰任何数据,而是不再提供服务,直接返回错误
  • LRU:最近最少使用(其实更准确的描述应该是最近未被访问过的key)
  • LFU:最近最不常用(Redis 4.0后新增).

触发条件:

在配置文件 redis.conf 中,可通过参数 maxmemory <bytes> 来设定最大运行内存。只有在Redis的运行内存达到了我们设置的最大运行内存,才会触发内存淘汰策略。

1、LRU(Least Recently Used):

最近最少使用,会选择淘汰最近最少使用的数据。

传统的LRU算法:基于哈希链表的结构,按照最后操作key(包含读key或写key操作)的时间顺序来排列。链表头进尾出,最新被操作的键会被移除并重新插入到链表头部。所以触发内存淘汰策略时,哈希链表的尾部就是 最久未被操作过 的元素,直接删除淘汰即可。

Redis的LRU类似于此方式,但为了节省内存做了改进,不完全相同…(具体参考 来自小林大佬的文章

  • 底层的Redis结构体对象中有最后访问时间戳相关字段

2、LFU(Least Frequently Used):
最近最不常用的,LFU 算法是根据数据访问频率(并非单纯的访问次数)来淘汰数据的,它的核心思想是 “如果数据过去被访问多次,那么将来被访问的频率也更高”。

  • 底层的Redis结构体对象中有访问频次相关字段