Redis 的 key 的过期策略是怎么实现的【经典面试题】

19 篇文章 0 订阅

前言

        在 Redis 中可以通过命令 expire 对指定的 key 值设置过期时间,在时间到了以后该键值对就会自动删除。

        一个 Redis 中可能会存在很多的 key ,而这些 key 中有很大的一部分都会有过期时间,那么 Redis 怎么知道哪些 key 已经到了过期时间需要删除,哪些 key 还没到过期时间呢?

        有读者可能会说,遍历不就得了,遍历 Redis 中所有的数据,就知道哪些数据已经到时间需要删除,哪些数据还没到时间。但这个方法显然是不行的,因为遍历一遍 Redis 中所有的数据非常的消耗时间和资源,而且还需要不停的遍历。

实现策略

        redis 整体的策略是:1.惰性删除  2.定期删除

惰性删除

        当一个 key 已经到过期时间时,暂时不删除该键值对,直到下次用户访问这个 key 值,才发现该 key 值已经过期,系统就顺便将该键值对删除,并且返回给用户 nil ,表示数据不存在。

定期删除

        规定一个定期删除数据的时间,比如每周删一次,并且删除过程中不是遍历 Rrdis 中所有的键值对,而是抽取一部分键值对,将其中过期的键值对进行删除,要保证定期删除的过程要足够快

        为什么对定期删除的速度有较高的要求呢?

        因为如果定期删除需要遍历 Redis 中所有的数据,将全部过期的键值对都找出来进行删除,那么在 Redis 中的数据很多的情况下,这个过程就会持续很久,而 Redis 是单线程的程序,此时在进行定期删除时,无法同时处理用户传来的请求,这就会导致阻塞,Redis 通常作为缓存,那么如果 Redis 出现了阻塞,就会导致大量的用户请求涌入数据库,很可能导致数据库直接挂掉,会造成很大的损失。

补充

        虽然有了上述的两种策略结合但整体的效果一般,仍然可能有许多过期的 key 值残留,没有被及时删除掉,redis 为了对上述进行补充,还用到了许多的内存淘汰策略

定时删除

        可能有某些文章会提到 Redis 使用了定时删除的策略,但这里明确的说,Redis 中并没有用到定时删除的策略,但定时删除也是可以实现 key 的过期策略的,而且也比较优秀,这里来简单介绍一下

        定时器:在指定的时间到达后,执行对应的任务

        假设在设置 key 的过期时间的同时,为该 key 创建一个定时器,让定时器在 key 的过期时间来临时将 key 删除

        优点:保证内存被尽快的释放

        缺点:如果过期的 key 很多,删除这些 key 就会消耗很多的 CPU 资源。定时器的创建很消耗时间和资源,若为每一个有过期时间的 key 都创建一个定时器,将会有大量的定时器产生,性能影响严重

        要想高效的通过定时删除实现 key 的过期策略,有两个比较优秀的方法

1.基于优先级队列/堆

        优先级队列也叫堆,分为大根堆和小根堆,堆顶的数据是最大/最小的。

        假设现在有许多的 key 都设置了过期时间,将这些 key 都添加到优先级队列中,指定优先级规则为 key 的过期时间最早的在堆顶,也就是以 key 的过期时间来建立小根堆

        由于在优先级队列中,堆顶的 key 是过期时间最早的,所以只要堆顶的 key 还没过期,其他的 key 也不会过期,此时定时器中只要分配一个线程,让这个线程去检查堆顶元素是否过期即可,此时线程不需要遍历所有的 key

        另外,线程检查堆顶元素是否过期也不能检查得太频繁,因为要是不停的去检查堆顶元素是否过期浪费了许多的 CPU 资源,好的做法是,根据当前时刻和堆顶元素的过期时间来设置一个等待时间,当等待时间到了以后,再唤醒线程

        但此时会出现一个问题,如果在线程等待的时候,有一个新的 key 值插入堆,并且过期时间比堆顶 key 的过期时间还早,那么线程要是还继续等待的话,堆顶的 key 已经过期很久了,所以当有新的 key 插入时,要唤醒线程,key 插入以后重新根据当前的时间和堆顶 key 的过期时间来设置线程的等待时间

2.基于时间轮来实现定时删除

        

        把时间划分成很多的小段,划分的粒度看具体的要求,每个小段上都挂着一个链表,每个链表表示一个要执行的任务,假设需要添加一个 key,这个 key 在 300 ms 后过期,那么这个 key 就会挂在 3 号链表上,如果 key 的过期时间很长,假设有 600 ms,那么就循环,挂在 1 号 链表上

        在时间轮上,有一个指针,从 1 号链表开始遍历,每走到一个链表,就把这个链表上的 key 检查一下,看有没有过期的,有过期的就删除,然后继续遍历。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Redis实现过期策略的方式有多种。 引用提到,当我们设置一个key过期时间时,Redis会将该键带上过期时间存放到一个过期字典中。当key过期后,如果没有触发Redis的删除策略过期后的数据依然会保存在内存中。这意味着,即使这个key已经过期,我们仍然能够获取到这个key的数据。 除了根据过期时间删除数据外,Redis还有其他的过期策略。具体有以下三种过期策略: 1. 定时删除:在设置key的同时,设置一个定时器,在过期时间到达时删除key。 2. 惰性删除:当某个客户端尝试获取一个已经过期key时,Redis会立即删除该key。 3. 定期删除:Redis会周期性地随机抽取一部分key,并检查其过期时间。如果过期,则删除。 需要注意的是,Redis并不是实时删除过期的数据,而是根据具体的策略来删除。这也是为了保证Redis的性能和效率。 因此,通过配置过期时间和选择合适的过期策略,可以实现Redis过期机制,防止数据累加后大量占用存储空间的问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Redis--Redis数据过期策略详解](https://blog.csdn.net/weixin_44074051/article/details/127266404)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [【RedisRedis过期策略以及内存淘汰机制详解](https://blog.csdn.net/weixin_42201180/article/details/129150967)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小林想被监督学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值