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

【redis】type命令和定时器的两种实现方式(优先级队列、时间轮)

type——返回 key 对应的数据类型

此处 Redis 所有的 key 都是 string,但是 key 对应的 value 可能会存在多种类型

  • none —— key 不存在
  • string ——字符串
  • list ——列表
  • set ——集合
  • zset ——有序集合
  • hash ——哈希表
  • stream ——Redis 作为消息队列的时候,使用这个类型的 value
    image.png|100

Redis 中,上述操作方式差别很大,使用的命令都是完全不同的

定时器

定时器:在某个时间到达之后,执行指定的任务

基于优先级队列/堆

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


什么叫优先级高?这个是自定义的

  • redis 过期 key 的场景中,就可以通过“过期时间越早,优先级越高”来进行约定

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

  • key1:12:00
  • key2:13:00
  • key3:14:00
    此时定时器中只要分配一个线程,让这个线程去检查队首元素,看是否过期即可。如果队首元素还没过期,则后续元素一定没过期。
  • 此时“扫描线程“不需要遍历所有的 key,只要盯住这一个队首元素即可。
  • 另外再扫描线程检查队首元素过期时间的时候,也不能检查的太频繁,不然 CPU 就空转了。
  • 此时我们可以根据当前时刻和队首元素的过期时间,来设置一个等待(主动阻塞),当时间差不多到了,系统再唤醒这个线程
  • 此时扫描线程不需要高频扫描队首元素,把 CPU 的开销也节省下来了

万一在休眠的时候,突然来了一个新的任务要执行怎么办呢?

  • 我们可以在添加新任务的时候,唤醒一下刚才的线程,重新检查一下对手元素,再根据时间差距重新调整阻塞时间即可

基于时间轮

把时间划分成很多小段(划分的粒度,看实际需求)

image.png

  • 每个小段上都挂着一个链表,每个链表都代表一个要执行的任务(在 java 中可以通过对象来实现类似的效果)
  • 此时这个指针,每隔固定的间隔(此处是约定 100ms),每次走到一个格子,就会把这个格子上链表的任务尝试执行一下
  • 假设需要添加一个 key,这个 key300ms 之后过期,那就停留在第三个格子之上,执行第三个格子的任务。就将第三个格子里的任务设置成 del key 即可

假设指定的过期时间特别长,3000ms,就围着轮子一直转,直到到达时间停止

对于时间轮来说,每个格子是多少时间,一共是多少个格子,都是需要根据实际场景,灵活调配的

Redis 没有采取上述的方案

ttl——查询过期时间

time to live

在网络原理,IP 协议报头中,就有一个 TTL 字段

  • IP 中的 TTL 不是用时间衡量过期的,而是次数

查询当前 key 的过期时间还剩多少
语法:

ttl key    //秒
pttl key   //毫秒
  • 返回剩余过期时间
  • 返回 -1 表示没有关联过期时间
  • 返回 -2 表示 key 不存在

过期策略是如何实现的

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

  • 如果直接遍历所有的 key,显然是行不通的,效率非常低
  • Redis 整体的策略是两方面
    1. 定期删除
    2. 惰性删除

惰性删除

  • 假设这个 key 已经到达过期时间了,但是暂时还没删除它,key 还在
  • 紧接着,后面又一次访问,正好用到了这个 key,于是这次访问就会让 Redis 服务器触发删除 key 的操作,同时再放回一个 nil
  • 你去超市买水,正要付钱的时候,看了一眼日期,发现过期了,于是老板就说不卖了,于是就把这瓶水下架了,这就是“惰性删除
  • 老板也不清楚哪些过期了,哪些没过期,就在卖出的时候做一次检查,如果过期了就不卖了,如果还没过期,就继续卖

但显然,单靠惰性删除肯定是不靠谱的,一个超市这么多商品,怎么可能全去靠用户去检查,所以肯定还得要有一个辅助的机制——定期删除

定期删除

这个超市老板,要定期查看超市里面的商品,看是否有过期产品

  • 但是如果超市商品很多,那么每次遍历一遍就非常慢
  • 所以,每次抽取一部分,进行验证过期时间。保证抽取检查的过程足够快

为什么这对定期删除的时间有明确的要求呢?

  • 因为 Redis 是单线程程序,主要的任务是处理每个命令的任务(刚才扫描过期 key…)
  • 如果扫描过期 key 消耗的时间太多了,就可能导致正常处理请求命令就被阻塞了(产生了类似 key * 的效果)

虽然有了上述两种策略结合,但整体的效果仍一般。仍然有可能会有很多过期的 key 被残留了,没有及时删除掉

但是 Redis 为了对上述进行补充,还提供了一系列的内存淘汰策略

相关文章:

  • elasticsearch是哪家的
  • 每天五分钟深度学习pytorch:基于Pytorch搭建ResNet模型的残差块
  • 分布式ETCD面试题及参考答案
  • 2025 年 AI 网络安全预测
  • 使用 Java 在后端 为 PDF 添加水印
  • 电脑中本地部署阉割版DeepSeek或其他大模型的方法
  • ES-分词器安装与使用详解
  • MWC 2025 | 移远通信推出AI智能无人零售解决方案,以“动态视觉+边缘计算”引领智能零售新潮流
  • Hive的架构
  • Python 相对路径写法
  • 掌握MiniQMT:程序化下单与撤单的高效实现
  • 【vLLM 教程】使用 TPU 安装
  • 《Natural Actor-Critic》译读笔记
  • DMR协议空中接口部分
  • Vulnhub-election靶机
  • shell编程——运算符和运算命令
  • 硬件基础(4):(1)AD采集电路设计
  • <论文>MiniCPM:利用可扩展训练策略揭示小型语言模型的潜力
  • Tomcat 使用与调优全解析
  • [Linux]进程
  • 纪念|演员朱媛媛:她的表演将日常琐碎升华为艺术真实
  • 淡出政治舞台?马斯克称将削减政治开支:已经做得够多了
  • 是否担心关税战等外部因素冲击中国经济?外交部:有能力、有条件、有底气
  • 演员辛柏青发讣告,妻子朱媛媛去世
  • 中国海警就菲向非法“坐滩”仁爱礁军舰运补发表谈话
  • 复旦兼职教授高纪凡首秀,勉励学子“看三十年才能看见使命”