redis 从0到1完整学习 (十六):内存回收之 key 过期处理策略

文章目录

  • 1. 引言
  • 2. redis 源码下载
  • 3. redisDb 结构体
  • 4. Redis 过期 key 的处理策略
    • 4.1 惰性删除 (Lazy Expiration)
    • 4.2 定期删除 (Active Expire / Periodic Expiration)*
  • 5. 参考


1. 引言

前情提要:
《redis 从0到1完整学习 (一):安装&初识 redis》
《redis 从0到1完整学习 (二):redis 常用命令》
《redis 从0到1完整学习 (三):redis 数据结构》
《redis 从0到1完整学习 (四):字符串 SDS 数据结构》
《redis 从0到1完整学习 (五):集合 IntSet 数据结构》
《redis 从0到1完整学习 (六):Hash 表数据结构》
《redis 从0到1完整学习 (七):ZipList 数据结构》
《redis 从0到1完整学习 (八):QuickList 数据结构》
《redis 从0到1完整学习 (九):SkipList 数据结构》
《redis 从0到1完整学习 (十):RedisObject 数据结构》
《redis 从0到1完整学习 (十一):RedisObject 之 String 类型》
《redis 从0到1完整学习 (十二):RedisObject 之 List 类型》
《redis 从0到1完整学习 (十三):RedisObject 之 Set 类型》
《redis 从0到1完整学习 (十四):RedisObject 之 ZSet 类型》
《redis 从0到1完整学习 (十五):RedisObject 之 Hash 类型》

之前我们介绍了很多 redis 的 value 类型,包含 String、Set、Hash、List 等等,本文主要介绍 redis 的 key 过期处理策略,包含惰性清理、定期清理。

2. redis 源码下载

Redis 源码可以点击这里下载,方便查看其中定义的一些数据结构。
在这里插入图片描述

3. redisDb 结构体

Redis 数据库在 Redis 内部实现上是通过 redisDb 结构体来表示的。redisDb 结构体包含了特定数据库实例的所有信息,包括其键值对、过期时间、以及其它与该数据库相关的属性和功能。

源码结构体如下:
在这里插入图片描述

redisDb 结构体详细介绍:

typedef struct redisDb {
    dict *dict; // 一个字典,存储数据库中的所有键值对,键为 SDS 字符串,值为 redisObject 指针
    dict *expires; // 一个字典,存储了具有过期时间的键及其对应的 UNIX 时间戳
    dict *blocking_keys; // (如果支持事务阻塞的话)记录了正处于阻塞状态的键
    dict *watched_keys; // (如果支持 WATCH 命令的话)记录了被客户端监视的键
    int id; // 数据库编号,默认情况下 Redis 有 16 个数据库,编号从 0 到 15
    long long avg_ttl; // 平均剩余生存时间(TTL),用于统计分析和优化定期删除策略
    /* 其他相关字段 */
} redisDb;

具体字段可能会随着 Redis 不同版本而有所增减或调整。每个 redisDb 结构体代表 Redis 中的一个逻辑数据库,并且这些数据库都存放在全局的 redisServer 结构体的 db 数组中。用户可以通过 SELECT 命令切换到不同的数据库进行操作。

4. Redis 过期 key 的处理策略

Redis 源码中对于过期 key 的处理主要包括两种策略:惰性删除(Lazy Expiration)和定期删除(Active Expire)。

4.1 惰性删除 (Lazy Expiration)

当客户端尝试访问一个已过期的 key 时,Redis 会在返回给客户端 key 值之前检查该 key 是否已过期。如果发现 key 已过期,则会立即从数据库中删除该 key,并返回相应的响应(如 nil 表示不存在 key)。这种方式资源消耗少,但会导致过期 key 在被访问前一直占用内存空间。

robj *lookupKeyWriteWithFlags(redisDb *db, robj *key, int flags) {
	   // 检查key是否过期,过期如果是惰性删除策略,则删除
	    expireIfNeeded(db,key);
	    return lookupKey(db,key,flags);
}

int expireIfNeeded(redisDb *db, robj *key) {
	// 没有过期,返回
    if (!keyIsExpired(db,key)) return 0;
	
	...
	// 过期了,删除
    int retval = server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :
	...                                  	
}

4.2 定期删除 (Active Expire / Periodic Expiration)*

Redis 通过后台线程周期性地从数据库中随机抽取一定数量的 key 进行检查,以主动清理过期 key。这个过程由 redis.c 文件中的 expireIfNeeded() 函数在每次访问 key 时触发,以及由 db.c 文件中的 activeExpireCycle() 函数按照配置的周期来执行。Redis 使用一个名为“过期字典”(expired dict)的数据结构存储了所有设置了过期时间的 key 和它们对应的过期时间戳。

具体实现如下:

  1. Redis 定义了一个名为 activeExpireCycle 的函数,该函数会周期性地被调用,通常是由 Redis 主进程中的定时任务或者事件驱动触发。

  2. activeExpireCycle 函数会选择一定数量的数据库进行遍历,并对每个数据库中的一部分 key 进行随机抽样检查其过期时间。

  3. 检查过程中,Redis 会根据当前时间和 key 的过期时间戳判断 key 是否已过期。如果发现某个 key 已经过期,则立即将其从数据库中删除。

  4. Redis 会动态调整这个清理过程的速度和范围,以尽量保证不过于频繁地消耗 CPU 资源,同时又能及时清理掉大量过期的 key,避免内存资源浪费。执行周期有两种模式:

    • SLOW 模式规则:
      • 执行频率受 server.hz 影响,默认为10,即每秒执行10次,每个执行周期100ms。
      • 执行清理耗时不超过一次执行周期的25%。默认 slow 模式耗时不超过25ms
      • 逐个遍历 db,逐个遍历 db 中的 bucket,抽取20个 key 判断是否过期
      • 如果没达到时间上限(25ms)并且过期 key 比例大于10%,再进行一次抽样,否则结束
    • FAST 模式规则(过期 key 比例小于10%不执行 ):
      • 执行频率受 beforeSleep() 调用频率影响,但两次FAST模式间隔不低于2ms
      • 执行清理耗时不超过1ms
      • 逐个遍历 db,逐个遍历 db中的 bucket,抽取20个 key 判断是否过期
        如果没达到时间上限(1ms)并且过期 key 比例大于10%,再进行一次抽样,否则结束
  5. 在实际操作中,Redis 也会根据服务器的负载情况、已使用内存与 maxmemory 设置等因素灵活调整清理策略,确保系统性能和资源的有效利用。

总的来看,定期删除是一种主动但又较为温和的过期 key 清理策略,它配合惰性删除共同维护了 Redis 内存的高效管理。
这两种机制结合使用可以确保 Redis 在不过度消耗 CPU 资源的情况下,有效地管理过期 key,从而避免内存浪费。同时,Redis 也会尽可能保证过期数据不会长时间不被清理。

5. 参考

《redis 从0到1完整学习 (一):安装&初识 redis》
《redis 从0到1完整学习 (二):redis 常用命令》
《redis 从0到1完整学习 (三):redis 数据结构》
《redis 从0到1完整学习 (四):字符串 SDS 数据结构》
《redis 从0到1完整学习 (五):集合 IntSet 数据结构》
《redis 从0到1完整学习 (六):Hash 表数据结构》
《redis 从0到1完整学习 (七):ZipList 数据结构》
《redis 从0到1完整学习 (八):QuickList 数据结构》
《redis 从0到1完整学习 (九):SkipList 数据结构》
《redis 从0到1完整学习 (十):RedisObject 数据结构》
《redis 从0到1完整学习 (十一):RedisObject 之 String 类型》
《redis 从0到1完整学习 (十二):RedisObject 之 List 类型》
《redis 从0到1完整学习 (十三):RedisObject 之 Set 类型》
《redis 从0到1完整学习 (十四):RedisObject 之 ZSet 类型》
《redis 从0到1完整学习 (十五):RedisObject 之 Hash 类型》

欢迎关注本人,我是喜欢搞事的程序猿; 一起进步,一起学习;

也欢迎关注我的wx公众号:一个比特定乾坤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/304577.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年如何使用WordPress构建克隆Udemy市场

您想创建像 Udemy 这样的学习管理 (LMS) 网站吗?最好的学习管理系统工具LifterLMS将帮助您制作像Udemy市场这样的 LMS 网站。 目录 Udemy市场是什么? 创建 Udemy 克隆所需的几项强制性技术: 步骤 1) 注册您的域名 步骤 2) 获取虚拟主…

JHipster - Spring Boot 的快速开发利器

产品介绍: JHipster是一个开源的、全面的应用程序生成器,它能够帮助开发者快速生成Spring Boot Angular/React/Vue.js的完整应用程序。它不仅提供了一个简单的界面来定义应用程序的配置,还提供了一组强大的代码生成器,可以在数分…

Taro+vue3 实现电影切换列表

1.需求 我们在做类似于猫眼电影的小程序或者H5 的时候 我们会做到那种 左右滑动的电影列表,这种列表一般带有电影场次 2.效果 3.说明 这种效果在淘票票 猫眼电影上 都有的 ,一般电影类型的H5 或者小程序 这个是都有的 第一是好看 第二是客观性比较好 …

Python 工具 | conda 基本命令

Hi,大家好,我是源于花海。本文主要了解 Python 的工具的 conda 相关的基本命令。Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。在Windows下,需要安装…

杨中科 ASP.NET Core 中的依赖注入的使用

ASP.NET CORE中服务注入的地方 1、在ASP.NET Core项目中一般不需要自己创建ServiceCollection、IServiceProvider。在Program.cs的builder.Build()之前向builderServices中注入 2、在Controller中可以通过构造方法注入服 务。 3、演示 新建一个calculator类 注入 新建TestC…

使用 PHP-FFMpeg 操作视频/音频文件

做音频合成的时候找到的一个php操作ffmpeg 的类库。GitHub地址:https://github.com/PHP-FFMpeg/PHP-FFMpeg/。本文的例子大部分都是上面的 在使用之前请安装好 FFMpeg 。如何安装?请看 FFmpeg 安装教程。 使用composer快速安装 > composer require …

Arcgis像元统计数据

目录 单幅影像统计多幅影像统计 单幅影像统计 现有一幅NDVI影像,如何知道影像中NDVI的分布情况呢? 先栅格转点,然后在属性表中查看汇总情况 还有一种方法就是在ENVI中打开, -0.3-0.338占据了99% 多幅影像统计 现有多幅NDVI影…

设置flex布局的元素,其子元素宽度和超过其本身时,其宽度值未被撑起问题

如图父元素main-content设置了display:flex. 里面包含了不确定个数的子元素,子元素样式为: flex: 1; min-width: 240px;现在想获取父元素的宽度,发现无论子元素的个数为多少,父元素的宽度都是一样的大小,并没有被子元…

使用 CompletableFuture 分批处理任务

一、无返回值任务函数 // 数据分批 List<List<StatisticsDTO>> batches Lists.partition(statisticsList, BATCH_SIZE); List<CompletableFuture<Void>> futures new ArrayList<>(batches.size());// 数据处理 for (int i 0; i < batches…

初学者的基本 Python 面试问题和答案

文章目录 专栏导读1、什么是Python&#xff1f;列出 Python 在技术领域的一些流行应用。2、在目前场景下使用Python语言作为工具有什么好处&#xff1f;3、Python是编译型语言还是解释型语言&#xff1f;4、Python 中的“#”符号有什么作用&#xff1f;5、可变数据类型和不可变…

imgaug库指南(12):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

【PB续命06】JDBC连接Oracle数据库

JDBC(Java DataBase Connectivity) 称为Java数据库连接&#xff0c;它是一种用于数据库访问的应用程序API&#xff0c;由一组用Java语言编写的类和接口组成&#xff0c;有了JDBC就可以用同一的语法对多种关系数据库进行访问&#xff0c;而不用担心其数据库操作语言的差异。 有了…

Git分支学习

Commit 每次 Commit &#xff0c;都会多一个节点&#xff0c;C1是C2的父节点&#xff0c;在C1的基础上产生。 使用 git commit 提交代码分支。 Branch 根据逻辑分解工作到不同的分支&#xff0c;在将分支和提交记录结合起来后&#xff0c;我们会看到两者如何协作。 在 mai…

KazooClient出现【句柄无效】错误

报错信息&#xff1b; Connection dropped: socket connection error: 句柄无效。 Connection dropped: socket connection error: 句柄无效。 Connection dropped: socket connection error: 句柄无效。 Connection dropped: socket connection error: 句柄无效。 Connection …

一夜爆火,3天60亿,这泼天的富贵也轮到我们尔滨了

近日&#xff0c;哈尔滨这座北国之城突然成为全国瞩目的焦点&#xff0c;一夜之间&#xff0c;冰雪大世界、索菲亚大教堂、中央大街等老牌旅游景点在网络短视频和游客们的热切关注下&#xff0c;成为了这个冬季的新“顶流”。当地市民姚先生和胡先生异口同声表示&#xff1a;“…

new mars3d.graphic.CloudPrimitive({实现移动的积云云图效果

问题说明&#xff1a; 1.在Mars3d的示例中找到了【积云】的效果&#xff0c;查看【积云】的api的时候&#xff0c;发现了支持属性机制的property属性。 相关api链接&#xff1a; CloudPrimitive - V3.7.0 - Mars3D API文档 2.但是不知道该属性机制如何使用&#xff0c;于是翻…

最全最详细ChatGPT预设词Prompt教程

使用指南 1、可直复制使用 2、可以前往已经添加好Prompt预设的AI系统测试使用&#xff08;可自定义添加使用&#xff09; https://ai.sparkaigf.com 雅思写作考官 我希望你假定自己是雅思写作考官&#xff0c;根据雅思评判标准&#xff0c;按我给你的雅思考题和对应答案给我…

揭秘!更适合“SaaS体质”的用户反馈收集方式

用户反馈是收集用户需求最直观也是最有效的方法之一。特别是SaaS企业&#xff0c;经常需要收集用户反馈&#xff0c;再从中提取出真实需求进行产品或服务的迭代和升级。然而&#xff0c;在服务了多家SaaS企业之后&#xff0c;我们发现&#xff0c;无法在短时间内收集到足够多的…

CRM系统是否适合企业,有哪些判断标准?

现如今&#xff0c;以客户为中心不再是一句空话&#xff0c;哪个企业能与客户建立长久的关系&#xff0c;那它就能获得业绩的增长。CRM管理系统的初衷就是维护客户关系&#xff0c;通过深入了解客户&#xff0c;提高转化率&#xff0c;并推动业绩增长。企业在选型时&#xff0c…

Win提示“d3dx9_27.dll文件缺失,程序无法启动运行”,修复大全

d3dx9_27.dll是一个被多个软件和游戏共享的动态链接库文件&#xff0c;主要用于Microsoft DirectX软件的功能。它是DirectX 9的一部分&#xff0c;DirectX是一种使得Windows成为理想平台进行高性能多媒体和游戏的API。 d3dx9_27.dll主要与计算机图形和视频渲染有关&#xff0c…