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

深入理解Redis:如何设置缓存数据的过期时间及其背后的机制

目录

Redis 给缓存数据设置过期时间

Redis是如何判断数据是否过期的呢?

过期的数据的删除策略

Redis 内存淘汰机制


Redis 给缓存数据设置过期时间

一般情况下,我们设置保存的缓存数据的时候都会设置一个过期时间。为什么呢?

因为内存是有限的,如果缓存中的所有数据都是一直保存的话,分分钟直接Out of memory。

Redis 自带了给缓存数据设置过期时间的功能,比如:

127.0.0.1:6379> exp key  60 # 数据在 60s 后过期
(integer) 1
127.0.0.1:6379> setex key 60 value # 数据在 60s 后过期 (setex:[set] + [ex]pire)
OK
127.0.0.1:6379> ttl key # 查看数据还有多久过期
(integer) 56

注意:Redis中除了字符串类型有自己独有设置过期时间的命令 setex 外,其他方法都需要依靠 expire 命令来设置过期时间 。另外, persist 命令可以移除一个键的过期时间:

过期时间除了有助于缓解内存的消耗,还有什么其他用么?

很多时候,我们的业务场景就是需要某个数据只在某一时间段内存在,比如我们的短信验证码可能只在1分钟内有效,用户登录的 token 可能只在 1 天内有效。

如果使用传统的数据库来处理的话,一般都是自己判断过期,这样更麻烦并且性能要差很多。

Redis是如何判断数据是否过期的呢?

Redis 通过一个叫做过期字典(可以看作是hash表)来保存数据过期的时间。过期字典的键指向Redis数据库中的某个key(键),过期字典的值是一个long long类型的整数,这个整数保存了key所指向的数据库键的过期时间(毫秒精度的UNIX时间戳)。

过期字典是存储在redisDb这个结构里的:

typedef struct redisDb {...dict *dict;     //数据库键空间,保存着数据库中所有键值对dict *expires   // 过期字典,保存着键的过期时间...
} redisDb;

过期的数据的删除策略

如果假设你设置了一批 key 只能存活 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?

常用的过期数据的删除策略就两个:

  1. 惰性删除 :只会在取出key的时候才对数据进行过期检查。这样对CPU最友好,但是可能会造成太多过期 key 没有被删除。

  2. 定期删除 : 每隔一段时间抽取一批 key 执行删除过期key操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。

定期删除对内存更加友好,惰性删除对CPU更加友好。两者各有千秋,所以Redis 采用的是 定期删除+惰性/懒汉式删除

但是,仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里,然后就Out of memory了。

怎么解决这个问题呢?答案就是: Redis 内存淘汰机制。

Redis 内存淘汰机制

Redis 提供 6 种数据淘汰策略:

  1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  4. allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)

  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

4.0 版本后增加以下两种:

  1. volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰

  2. allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key

相关文章:

  • Arduino EC11编码器驱动库使用示例介绍
  • 深度学习模型:GAN(生成对抗网络)
  • 苹果笔记本MacBook电脑怎么卸载软件?三种方法快速卸载软件
  • C++逆向分析--虚函数(多态的前置)
  • 【Midjourney】绘画风格关键词
  • Python编程 从入门到实践(项目二:数据可视化)
  • Docker 配置 Gitea + Drone 搭建 CI/CD 平台
  • jQuery取整(Math.floor()、Math.ceil() 、 parseInt() )
  • Spring Boot 项目的创建和启动
  • LeetCode 刷题总结 【未完待续】
  • 应用案例:Ruff工业设备数据采集,为生产制造企业数字化转型赋能
  • 工厂方法模式-C#实现
  • 浮点数在内存中存储
  • 【mongoDB】文档 CRUD
  • VR漫游:赋予用户720度身临其境的沉浸式体验
  • FineReport中如何实现自动滚屏效果
  • IP路由与转发
  • Redis 中的布隆过滤器
  • spark本地环境的搭建到运行第一个spark程序
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 测试如何在敏捷团队中工作?
  • 理解在java “”i=i++;”所发生的事情
  • 如何用vue打造一个移动端音乐播放器
  • 我与Jetbrains的这些年
  • 白色的风信子
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • Hibernate主键生成策略及选择
  • 说说我为什么看好Spring Cloud Alibaba
  • ​secrets --- 生成管理密码的安全随机数​
  • ​马来语翻译中文去哪比较好?
  • #QT(串口助手-界面)
  • (02)vite环境变量配置
  • (Java)【深基9.例1】选举学生会
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (一)VirtualBox安装增强功能
  • (转)http协议
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .bat批处理(一):@echo off
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .Net MVC4 上传大文件,并保存表单
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景
  • .py文件应该怎样打开?
  • .vollhavhelp-V-XXXXXXXX勒索病毒的最新威胁:如何恢复您的数据?
  • /bin、/sbin、/usr/bin、/usr/sbin
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [AI]文心一言爆火的同时,ChatGPT带来了这么多的开源项目你了解吗
  • [C#]猫叫人醒老鼠跑 C#的委托及事件
  • [HNOI2015]实验比较