Redis原理篇(四)内存回收

news2024/12/28 22:48:44

Redis之所以性能强,最主要原因是基于内存存储。但是单节点的Redis其内存大小不宜过大,会影响持久化或主从同步性能。

可以通过配置文件来设置最大内存

# maxmemory <bytes>
maxmemory  1gb

一、过期策略

可以通过expire命令给Redis的key设置TTL
在这里插入图片描述

思考:
1、Redis是如何知道一个key是否过期?
答:利用两个Dict分别记录key-value对,及key-ttl对。从key-value中获取到key,再到key-ttl对中查询。

2、是不是TTL到期就立即删除了?
答:惰性删除和周期删除

1、DB结构

Redis本身是一个典型的key-value内存存储数据库,因此所有的key、value都保存在Dict结构中。有两个Dict:一个记录key-value;另一个记录key-TTL
在这里插入图片描述
在这里插入图片描述

2、惰性删除

(1)定义

不是在TTL到期后就立刻删除,而是在访问一个key的时候,检查该key的存活时间,如果已经过期才执行删除。

// 查找一个key执行写操作
robj *lookupKeywritewithFlags(redisDb *db, robj *key, int flags) {
	// 检查key是否过期
	expireIfNeeded(db , key);
	return lookupkey(db , key, flags);
// 查找一个key执行读操作
robj *lookupKeyReadwithFlags(redisDb *db, robj *key, int flags) {
	robi *val;
	// 检查key是否过期
	if (expireIfNeeded(db,key) == 1) {
		// ...}
	return lookupKey(db ,key,flags);
}

int expireIfNeeded(redisDb *db, robj *key) {
    // 判断是否过期,如果未过期直接结束并返回0
	if (!keyIsExpired(db,key)) {
		return 0;
	} 
	// 删除过期key
	deleteExpiredKeyAndPropagate(db , key);
	return 1;
}

3、周期删除

(1)定义

通过一个定时任务,周期性的抽样部分过期的key,然后执行删除。执行周期有两种:

  • Redis会设置一个定时任务serverCron(),按照server.hz的频率来执行过期key清理,模式为SLOW
  • Redis的每个事件循环前会调用beforesleep0)函数,执行过期key清理,模式为FAST

SLOW源码

//server .c
void initServer(void){
	// 创建定时器,关联回调函数serverCron,处理周期取决于server,hz,默认10
	aeCreateTimeEvent(server.el,1,serverCron,NULL,NULL)
}

//server.c
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData){
	// 更新Lruclock到当前时间,为后期的LRU和LFU做准备
	unsigned int lruclock = getLRUClock();
	atomicSet(server.lruclock,lruclock);
	// 执行database的数据清理,例如过期key处理
	databasesCron();
	return 1000/server.hz:
}

void databasesCron(void) {
	// 尝试清理部分过期key,清理模默认为SLOW
	activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
}

FAST源码

void beforeSleep(struct aeEventLoop*eventLoop){
	// 尝试清理部分过期key,清理模式默认为FAST
	activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
}

void aeMain(aeEventLoop *eventLoop) {
	eventLoop->stop = 0;
	while (!eventLoop->stop) {
		// beforesleep() --> Fast模式清理
		// n = aeApiPoll()
		//如果n > 0,FD就绪,处理IO事件
		//如果到了执行时间,则调用serverCron() --> SLOW模式清理

(2)模式规则

SLOw模式规则:

  1. 执行频率受server.hz影响,默认为10,即每秒执行10次,每个执行周期100ms。
  2. 执行清理耗时不超过一次执行周期的25%.
  3. 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
  4. 如果没达到时间上限(25ms)并且过期key比例大于10%,再进行一次抽样,否则结束

FAST模式规则(过期key比例小于10%不执行):

  1. 执行频率受beforeSleep()调用频率影响,但两次FAST模式间隔不低于2ms
  2. 执行清理耗时不超过1ms
  3. 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
  4. 如果没达到时间上限(1ms)并且过期key比例大于10%,再进行一次抽样,否则结束

4、总结

1、RedisKey的TTL记录方式:
在RedisDB中通过一个Dict记录每个Key的TTL时间
2、过期key的删除策略:

  1. 惰性删除:每次查找key时判断是否过期,如果过期则删除
  2. 周期删除:定期抽样部分key,判断是否过期,如果过期则删除。

3、周期删除的两种模式:

  1. SLOW模式执行频率默认为10,每次不超过25ms
  2. FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms

二、内存淘汰策略

1、定义

内存淘汰:就是当Redis内存使用达到设置的阈值时,Redis主动挑选部分key删除以释放更多内存的流程。

(1)什么时候检查内存超出阈值?

答:任何Redis客户端命令执行时,都去检查内存,尝试做内存淘汰。
在这里插入图片描述

(2)如何挑选key

Redis支持8种不同策略来选择要删除的key:

策略说明
noeviction不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。
volatile-ttl对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰。
allkeys-random对全体key,随机进行淘汰。也就是直接从db->dict中随机挑选。
volatile-random对设置了TTL的key ,随机进行淘汰。也就是从db->expires中随机挑选。
allkeys-lru对全体key,基于LRU算法进行淘汰。
volatile-lru对设置了TTL的key,基于LRU算法进行淘汰。
allkeys-lfu对全体key,基于LFU算法进行淘汰。
volatile-lfu对设置了TTL的key,基于LFI算法进行淘汰。

比较容易混淆的有两个:

  • LRU(Least Recently Used):最少最近使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
  • LFU (Least Frequently Used):最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。

在这里插入图片描述

备注:
LFU的访问次数之所以叫做逻辑访问次数,是因为并不是每次key被访问都计数,而是通过运算:
1、生成0~1之间的随机数R
2、计算1/(旧次数*lfu_log_factor+ 1),记录为P,lfu_log_factor默认为10
3、如果R<P,则计数器+1,且最大不超过255
4、访问次数会随时间衰减,距离上一次访问时间每隔lfu_decay_time 分钟(默认1),计数器-1

修改策略

# conf配置文件
maxmemory-policy noeviction

2、淘汰策略流程

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++算法图解专栏】一篇文章带你掌握高精度加减乘除运算

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为 0 基础刚入门数据结构与算法的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们一起交流~ &#x1f4da;专栏地址&#xff1a;https://blog.csdn.net/Newin…

Java 异常 笔记

异常体系结构 异常分为Error和Exception。Error通常是灾难性错误&#xff0c;一般发生时&#xff0c;JVM选择终止程序执行&#xff1b;Exception通常可在程序中进行处理&#xff0c;尽量避免 Exception分支中有一个重要子类RuntimeException&#xff0c;运行时异常 ArrayInd…

数据库,计算机网络、操作系统刷题笔记34

数据库&#xff0c;计算机网络、操作系统刷题笔记34 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

深入理解Promise

Promise的前提概念 Promise是一个构造函数&#xff0c;用来生成Promise实例 Promise构造函数接受一个函数作为参数&#xff0c;该函数有两个参数&#xff0c;分别是resolve和reject resolve&#xff1a;成功时的回调 reject&#xff1a;失败时的回调 Promise分别有三个状态 1…

行人属性识别研究综述(一)

文章目录摘要1、简介2 问题的表述和挑战3 标准3.1 数据集3.2 评价标准4 行人属性识别的常规流程4.1 多任务学习4.2 多标签学习5 深度神经网络&#x1f407;&#x1f407;&#x1f407;&#x1f407;&#x1f407;&#x1f407;&#x1f407; 欢迎阅读 【AI浩】 的博客&#x1f…

C#上位机基础学习_基于S7.Net实现读取S7-1500PLC中的字符串变量

C#上位机基础学习_基于S7.Net实现读取S7-1500PLC中的字符串变量 如下图所示,首先在TIA博途中创建一个项目,添加一个1500PLC,添加一个DB块,在DB块中添加几个字符串变量, 如下图所示,打开Visual Studio 2019,新建一个项目,在Form1中添加一个按钮和一个文本框, 如下图…

linux——高级信号

高级信号的收发发&#xff1a;siquequ收&#xff1a;sigaction() 包含三个元素num,sigaction()函数&#xff0c;备份num ->signumsigaction是一个结构体&#xff0c;需额外配置再传进来备份直接忽略&#xff0c;代表不需要备份sigaction结构体又包含四个元素sa_handler&…

Git进阶:修改上次提交 git commit --amend

一、问题说明 git commit 后&#xff0c;发现刚才的备注写错了&#xff0c;或者代码漏掉了&#xff0c;这时我们肯定是想取消刚才的提交。此刻有两种方法 &#xff08;1&#xff09;使用git reset命令将刚才的提交会退掉。需要注意的是git reset --soft 和git reset --hard的区…

【附源码】国内首届Discord场景创意编程开源项目

以下开源项目是由环信联合华为举办的《国内首届Discord场景创意编程赛》作品&#xff0c;附源码&#xff0c;一键即用。 一、 模拟器游戏直播-新新人类 新新人类模拟器游戏直播基于环信超级社区Demo构建&#xff0c;增加以“video-x”命名的新型Channel&#xff0c;用户可在本…

Java三目运算符导致 NPE

在三目运算符中&#xff0c;表达式 1 和 2 在涉及算术计算或数据类型转换时&#xff0c;会触发自动拆箱。当其中的操作数为 null 值时&#xff0c;会导致 NPE 。 一、基础知识 三目运算符 三目运算符是 Java 语言中的重要组成部分&#xff0c;它也是唯一有 3 个操作数的运算…

Linux常用命令——tempfile命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tempfile shell中给临时文件命名 补充说明 有时候在写Shell脚本的时候需要一些临时存储数据的才做&#xff0c;最适合存储临时文件数据的位置就是/tmp&#xff0c;因为该目录中所有的内容在系统重启后就会被清…

LInux(三)程序地址空间、内存管理

目录 一、程序地址空间 二、内存管理方式 1、分段式内存管理 2、分页式内存管理 3、段页式内存管理 三、关于内存管理内容补充&#xff08;分页式&#xff09; 1、页表简单呈现 2、访问权限位 3、缺页中断 4.内存置换算法 一、程序地址空间 创建父子进程同时访问同一变量…

正式发布丨Azure OpenAI Service

Azure OpenAI 服务现已在微软全球 Azure 平台正式发布&#xff0c;这是微软人工智能大众化以及与 OpenAI 持续合作的又一里程碑。 大型语言模型正迅速成为用户无限创新、应用 AI 解决重要问题的平台。随着 Azure OpenAI 服务的正式发布&#xff0c;更多企业用户可以访问世界先…

在线支付系列【5】支付安全之数字证书

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录公钥信任问题数字证书颁发流程使用流程SSL数字证书HTTPSSSL/TLS 证书如何申请SSL 证书使用keytool 生成ssl证书通信过程公钥信任问题 之前我们使用对称、非对称加密、信息摘要、数字签名&#…

DPDK系列之一基础环境搭建

一、DPDK是什么 DPDK,Data Plane Development Kit&#xff0c;数据平面开发套装&#xff0c;它还有一个兄弟SPDK&#xff0c;专门用来做存储优化的。它主要运行于Linux&#xff0c;是由Intel几家公司共同开发&#xff0c;用于快速处理数据的一个网络开发工具套装。更详细的说明…

python数据清洗1

数据获取——》数据清洗——》数据转换——》数据分析 通过设置步长&#xff0c;有间隔的取元素通过设置步长为-1&#xff0c;将元素颠倒 数据清洗工具 目前在Python中, numpy和pandas是最主流的工具。 Numpy中的向量化运算使得数据处理变得高效&#xff1b;Pandas提供了大量…

【Java入门】Java数据类型

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java入门 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又一…

(十四)线程池

线程池线程池是一组线程的集合。线程池维护一个队列&#xff0c;调用者向这个队列中添加任务&#xff0c;而线程池中的线程则不停地从队列中取出任务执行。线程池的继承关系如下图&#xff0c;其中ThreadPoolExecutor和ScheduledThreadPoolExecutor是具体的实现。ThreadPoolExe…

LeetCode刷题模版:141 - 150

目录 简介141. 环形链表142. 环形链表 II143. 重排链表144. 二叉树的前序遍历145. 二叉树的后序遍历146. LRU 缓存【未实现】147. 对链表进行插入排序148. 排序链表149. 直线上最多的点数150. 逆波兰表达式求值结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方…

多轮对话(三):Spoken Language Understanding 进展和前沿

本篇博客基于哈工大发表在IJCAI上的论文&#xff1a;A Survey on Spoken Language Understanding - Recent Advances and New Frontiers。 论文链接 github链接 口语理解&#xff08;SLU&#xff09;旨在提取用户查询的语义框架&#xff0c;是面向任务的对话系统的核心组件。本…