当前位置: 首页 > news >正文

redis的过期策略和定时器

欢迎拜访:雾里看山-CSDN博客
本篇主题redis的过期策略和定时器
发布时间:2025.8.12
隶属专栏:redis

在这里插入图片描述

目录

  • redis的过期策略
    • 惰性删除
    • 定期删除
  • 如果大量的 key 在同一时间点过期, 会产生什么问题? 如何处理?
  • 定时器
    • 基于优先级队列的定时器
    • 基于时间轮实现的定时器

redis的过期策略

一个redis中可能同时存在很多很多的key,这些key中很大一部分都有过期时间,此时,redis服务器是怎么知道哪些key已经过期要被删除,哪些key还没过期?

如果直接遍历所有的key,显然是行不通的,这样的效率太低了。

redis的整体使用的策略由两种:

  1. 惰性删除
  2. 定期删除

惰性删除

假设这个key已经到了过期的时间,但是暂时还没删它,key还存在。
紧接着,后面又一次访问,正好用到了这个key,于是这次访问就会让redis服务触发删除key的操作,同时再返回一个nil。

该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

定期删除

每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是直接扫描和惰性删除的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。

因为redis是单线程的程序。如果扫描过期key消耗的时间太多了,就可能导致正常处理的请求命令被阻塞了(产生了类似于执行keys*这样的效果)。

如果大量的 key 在同一时间点过期, 会产生什么问题? 如何处理?

如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,Redis 可能会出现短暂的卡顿现象。

为何会出现卡顿呢? Redis 针对过期 key 的删除, 采取 定期采样删除 + 惰性删除 两种方式结合。

如果过期 key 的数目超过总 key 数目的 25% 以上, 就会使 Redis 持续删除过期 key 直到最大时间删除时间 (默认是 25ms)。

之所以限制这个最大时间, 就是为了防止 Redis 被卡住太久

但是即使如此, 有些对性能要求较高的场景仍然会因为阻塞 25ms 导致性能下降严重。

解决方案: 可以在过期时间上加一个随机值,使得过期时间分散一些。

很多时候过期时间并不一定非得卡的那么精准。比如设定 2s 之后过期, 不一定非要正好的 2000ms,2001, 2002, 1999, 1998 甚至 2010 这些时间都是问题不大的。

因此让过期时间通过随机值分散, 就可以避免同一时刻过期的 key 太多, 从而降低触发 25% 这个阈值的可能性.

定时器

redis中并没有采用定时器的方式来实现过期key删除的策略。

redis中没有使用定时器的原因:

基于定时器的实现,势必需要引入多线程,redis早起版本都是基于单线程的基调,引入多线程就打破了作者的初衷。

但是使用定时器的方案,在很多地方都可以用到,redis后续也不是没有可能引入计数器的可能。

以下是两种常用的定时器实现的方法:

基于优先级队列的定时器

正常的队列是先进先出,优先级队列则是按照指定的优先级先出。

优先级的高低是可以定义的,在redis的使用场景中,就可以使用过期时间越早,优先级越高

现在假设有很多的key设置了过期时间,就可以把这些key都加入到优先级队列当中,指定优先级规则是过期时间早的,先出队列。
这样,队首元素就是要最早过期的key!!!

key1: 12:00
key2: 13:00
key3: 14:00

此时,定时器中只需要分配一个线程,让这个线程去检查队首元素是否过期即可。如果队首元素没有过期,后续元素一定没过期!!

这样,扫描线程,不需要遍历所有的key,只盯住队首元素即可。

我们可以根据当前时刻和队首的过期时间设置一个等待,让线程进行休眠,当等待时间到了或者有新的任务来了,再唤醒这个线程。处理完之后,重新根据队首设置等待时间即可。

基于时间轮实现的定时器

把时间划分成多个小段(划分的粒度可以看实际的需求)。
在这里插入图片描述
每个小段上都挂着一个链表,每个节点都代表着一个要执行的任务。

假设需要设置一个key,这个key将在3000ms之后过期,我们就可以根据他在每个格子之间移动的速度,将他挂载到相应的位置。

如果指针每100ms移动一个格子,该时间轮有十二个格子,我们就可以将他挂载到当前位置后面的第六个格子,这样在过期的时间到了以后,我们的指针刚好在对应的格子里面,就可以执行相应的操作了。

对于时间轮来说,每个格子是多少时间,一共多少个格子,都是可以灵活调配的。

⚠️ 写在最后:以上内容是我在学习以后得一些总结和概括,如有错误或者需要补充的地方欢迎各位大佬评论或者私信我交流!!!

http://www.lryc.cn/news/618814.html

相关文章:

  • Cloud Computing(云计算)和Sky Computing(天空计算)
  • 地图可视化实践录:显示地理区域图
  • 深层神经网络
  • 测试匠谈 | AI语音合成之大模型性能优化实践
  • 【C#】用队列构建一个对象池管理对象的创建和释放
  • PySpark性能优化与多语言选型讨论
  • 各种 dp 刷题下
  • 人机交互:连接人类与数字世界的桥梁
  • apache+虚拟主机
  • 五、Elasticsearch在Linux的安装部署
  • Rust 项目编译故障排查:从 ‘onnxruntime‘ 链接失败到 ‘#![feature]‘ 工具链不兼容错误
  • 使用reqwest+select实现简单网页爬虫
  • Rust 性能提升“最后一公里”:详解 Profiling 瓶颈定位与优化|得物技术
  • open-webui源码分析1—文件上传
  • Vue接口平台十三——测试记录
  • springboot整合sharding-jdbc 5.5.2 做单库分表
  • 燕山大学计算机网络实验(2025最新)
  • Java调用Vue前端页面生成PDF文件
  • 深入剖析 React 合成事件:透过 onClick 看本质
  • Java 工厂方法模式
  • Flask + Vue.js 物联网数字大屏实现方案
  • 数据分析基本内容(第二十节课内容总结)
  • Rsync自动化备份平台建设实战
  • 【数据分析与挖掘实战】金融风控之贷款违约预测
  • 阿里云 Windows 服务器 搭建 Gitea 私有 Git 服务器完整教程
  • 开疆智能Ethernet转ModbusTCP网关连接PAC3200电能表配置案例
  • VirtualBox 虚拟机磁盘扩容完整手册
  • MaxKB+合合信息TextIn:通过API实现PDF扫描件的文档审核
  • [git] 重配ssh key | 解决冲突
  • python日志中的logging.basicConfig和logging.getLogger