当前位置: 首页 > 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.dtcms.com/a/328530.html

相关文章:

  • 支持任意 MCP 协议的客户端
  • SQL180 每类试卷得分前3名
  • Mybatis源码解读-Plugin插件源码
  • (C++)继承全解析及运用
  • Labelme从安装到标注:零基础完整指南
  • MySQL基础面试
  • Springboot整合Thrift
  • 移动端网页调试实战,键盘弹出与视口错位问题的定位与优化
  • 汉高携手SAP推出AI驱动的退换货与争议管理解决方案
  • 赛灵思ZYNQ官方文档UG585自学翻译笔记:UART Controller,通用异步收发传输器控制器
  • Vue接口平台十三——测试记录
  • Ubuntu 全盘备份
  • 九尾狐未来机械晶核技术
  • k3s部署
  • 电脑硬件详解
  • ZYNQ AXI-GPIO学习——ZYNQ学习笔记8
  • 学习游制作记录(背包UI以及各种物品的存储)8.12
  • kafka 消费者组的概念是什么?它是如何实现消息的点对点和发布/订阅模式?
  • Supabase快速入门与实战指南
  • LangChain 入门学习
  • Spring AI Alibaba - 聊天机器人快速上手
  • SpringAI 使用通义千问进行聊天对话开发
  • 考研复习-计算机组成原理-第五章-CPU
  • [NoC]Outstanding和Credit的概念详解
  • Fluent Bit 日志合并正则表达式(上)
  • Nginx 高级配置
  • Python训练Day41
  • 基于PAI-ChatLearn的GSPO强化学习实践
  • LLM - 搭建 Grounded SAM 2 模型的视觉检测与分割服务 API
  • CMake笔记:PUBLIC/PRIVATE/INTERFACE的使用