Redis中内存淘汰算法实现

Redis中内存淘汰算法实现

Redis的maxmemory支持的内存淘汰机制使得其成为一种有效的缓存方案,成为memcached的有效替代方案。

当内存达到maxmemory后,Redis会按照maxmemory-policy启动淘汰策略。

Redis 3.0中已有淘汰机制:

  • noeviction
  • allkeys-lru
  • volatile-lru
  • allkeys-random
  • volatile-random
  • volatile-ttl
maxmemory-policy含义特性
noeviction不淘汰内存超限后写命令会返回错误(如OOM, del命令除外)
allkeys-lru所有key的LRU机制 在所有key中按照最近最少使用LRU原则剔除key,释放空间
volatile-lru易失key的LRU仅以设置过期时间key范围内的LRU(如均为设置过期时间,则不会淘汰)
allkeys-random所有key随机淘汰一视同仁,随机
volatile-random易失Key的随机仅设置过期时间key范围内的随机
volatile-ttl易失key的TTL淘汰按最小TTL的key优先淘汰

其中LRU(less recently used)经典淘汰算法在Redis实现中有一定优化设计,来保证内存占用与实际效果的平衡,这也体现了工程应用是空间与时间的平衡性。

PS:值得注意的,在主从复制模式Replication下,从节点达到maxmemory时不会有任何异常日志信息,但现象为增量数据无法同步至从节点。

Redis 3.0中近似LRU算法

Redis中LRU是近似LRU实现,并不能取出理想LRU理论中最佳淘汰Key,而是通过从小部分采样后的样本中淘汰局部LRU键。

Redis 3.0中近似LRU算法通过增加待淘汰元素池的方式进一步优化,最终实现与精确LRU非常接近的表现。

精确LRU会占用较大内存记录历史状态,而近似LRU则用较小内存支出实现近似效果。

以下是理论LRU和近似LRU的效果对比:

在这里插入图片描述

  • 按时间顺序接入不同键,此时最早写入也就是最佳淘汰键
  • 浅灰色区域:被淘汰的键
  • 灰色区域:未被淘汰的键
  • 绿色区域:新增写入的键

总结图中展示规律,

  • 图1Theoretical LRU符合预期:最早写入键逐步被淘汰
  • 图2Approx LRU Redis 3.0 10 samples:Redis 3.0中近似LRU算法(采样值为10)
  • 图3Approx LRU Redis 2.8 5 samples:Redis 2.8中近似LRU算法(采样值为5)
  • 图4Approx LRU Redis 3.0 5 samples:Redis 3.0中近似LRU算法(采样值为5)

结论:

  • 通过图4和图3对比:得出相同采样值下,3.0比2.8的LRU淘汰机制更接近理论LRU
  • 通过图4和图2对比:得出增加采样值,在3.0中将进一步改善LRU淘汰效果逼近理论LRU
  • 对比图2和图1:在3.0中采样值为10时,效果非常接近理论LRU

采样值设置通过maxmemory-samples指定,可通过CONFIG SET maxmemory-samples 动态设置,也可启动配置中指定maxmemory-samples

源码解析

int freeMemoryIfNeeded(void){while (mem_freed < mem_tofree) {if (server.maxmemory_policy == REDIS_MAXMEMORY_NO_EVICTION)return REDIS_ERR; /* We need to free memory, but policy forbids. */if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM){......}/* volatile-random and allkeys-random policy */if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM ||server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_RANDOM){......}/* volatile-lru and allkeys-lru policy */else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU){// 淘汰池函数evictionPoolPopulate(dict, db->dict, db->eviction_pool);while(bestkey == NULL) {evictionPoolPopulate(dict, db->dict, db->eviction_pool);// 从后向前逐一淘汰for (k = REDIS_EVICTION_POOL_SIZE-1; k >= 0; k--) {if (pool[k].key == NULL) continue;de = dictFind(dict,pool[k].key); // 定位目标/* Remove the entry from the pool. */sdsfree(pool[k].key);/* Shift all elements on its right to left. */memmove(pool+k,pool+k+1,sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1));/* Clear the element on the right which is empty* since we shifted one position to the left.  */pool[REDIS_EVICTION_POOL_SIZE-1].key = NULL;pool[REDIS_EVICTION_POOL_SIZE-1].idle = 0;/* If the key exists, is our pick. Otherwise it is* a ghost and we need to try the next element. */if (de) {bestkey = dictGetKey(de); // 确定删除键break;} else {/* Ghost... */continue;}}}}/* volatile-ttl */else if (server.maxmemory_policy == EDIS_MAXMEMORY_VOLATILE_TTL) {......}// 最终选定待删除键bestkeyif (bestkey) {long long delta;robj *keyobj = createStringObject(bestkey,sdslenbestkey)); // 目标对象propagateExpire(db,keyobj);latencyStartMonitor(eviction_latency); // 延迟监控开始dbDelete(db,keyobj); // 从db删除对象latencyEndMonitor(eviction_latency);// 延迟监控结束latencyAddSampleIfNeeded("eviction-del",iction_latency); // 延迟采样latencyRemoveNestedEvent(latency,eviction_latency);delta -= (long long) zmalloc_used_memory();mem_freed += delta; // 释放内存计数server.stat_evictedkeys++; // 淘汰key计数,info中可见notifyKeyspaceEvent(REDIS_NOTIFY_EVICTED, "evicted", keyobj, db->id); // 事件通知decrRefCount(keyobj); // 引用计数更新keys_freed++;// 避免删除较多键导致的主从延迟,在循环内同步if (slaves) flushSlavesOutputBuffers();}}
}

Redis 4.0中新的LFU算法

从Redis4.0开始,新增LFU淘汰机制,提供更好缓存命中率。LFU(Least Frequently Used)通过记录键使用频率来定位最可能淘汰的键。

对比LRU与LFU的差别:

  • 在LRU中,某个键很少被访问,但在刚刚被访问后其被淘汰概率很低,从而出现这类异常持续存在的缓存;相对的,其他可能被访问的键会被淘汰
  • 而LFU中,按访问频次淘汰最少被访问的键

Redis 4.0中新增两种LFU淘汰机制:

  • volatile-lfu:设置过期时间的键按LFU淘汰
  • allkeys-lfu:所有键按LFU淘汰

LFU使用Morris counters计数器占用少量位数来评估每个对象的访问频率,并随时间更新计数器。此机制实现与近似LRU中采样类似。但与LRU不同,LFU提供明确参数来指定计数更新频率。

  • lfu-log-factor:0-255之间,饱和因子,值越小代表饱和速度越快
  • lfu-decay-time:衰减周期,单位分钟,计数器衰减的分钟数

这两个因子形成一种平衡,通过少量访问 VS 多次访问 的评价标准最终形成对键重要性的评判。

u-decay-time:衰减周期,单位分钟,计数器衰减的分钟数

这两个因子形成一种平衡,通过少量访问 VS 多次访问 的评价标准最终形成对键重要性的评判。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes基础(十六)-pod QoS等级

1 Pod Qos等级 一个节点不一定能提供所有pod所指定的资源limits之和那么多的资源量。 假设有两个pod,pod A使用了节点内存的 90%,pod B突然需要比之前更多的内存&#xff0c;这时节点无法提供足量内存&#xff0c;哪个容器将被杀掉呢&#xff1f;应该是pod B吗&#xff1f;因…

Office2013下载安装教程,保姆级教程,附安装包和工具

前言 Microsoft Office是由Microsoft(微软)公司开发的一套基于 Windows 操作系统的办公软件套装。常用组件有 Word、Excel、PowerPoint、Access、Outlook等。 准备工作 1、Win7 及以上系统 2、提前准备好 Office 2013 安装包 安装步骤 1.鼠标右击【Office2013(64bit)】压缩…

掌握Vue,开启你的前端开发之路!

介绍&#xff1a;Vue.js是一个构建数据驱动的Web应用的渐进式框架&#xff0c;它以简洁和轻量级著称。 首先&#xff0c;Vue.js的核心在于其视图层&#xff0c;它允许开发者通过简单的模板语法将数据渲染进DOM&#xff08;文档对象模型&#xff09;。以下是Vue.js的几个重要特点…

爬虫工作量由小到大的思维转变---<第四十五章 Scrapyd 关于gerapy遇到问题>

前言: 本章主要是解决一些gerapy遇到的问题,会持续更新这篇! 正文: 问题1: 1400 - build.py - gerapy.server.core.build - 78 - build - error occurred (1, [E:\\项目文件名\\venv\\Scripts\\python.exe, setup.py, clean, -a, bdist_uberegg, -d, C:\\Users\\Administrat…

[linux]:匿名管道和命名管道(什么是管道,怎么创建管道(函数),匿名管道和命名管道的区别,代码例子)

目录 一、匿名管道 1.什么是管道&#xff1f;什么是匿名管道&#xff1f; 2.怎么创建匿名管道&#xff08;函数&#xff09; 3.匿名管道的4种情况 4.匿名管道有5种特性 5.怎么使用匿名管道&#xff1f;匿名管道有什么用&#xff1f;&#xff08;例子&#xff09; 二、命名…

《女神异闻录3 Reload》评价怎么样?Mac电脑怎么玩《女神异闻录3 Reload》?女神异闻录3销量超100万 女神异闻录3攻略

Atlus官方于今日宣布&#xff0c;《女神异闻录3&#xff1a;Reload》的销量已经突破了100万份&#xff0c;为Atlus史上销售速度最快的作品。现在超人气游戏《女神异闻录3&#xff1a;Reload》在苹果电脑上也能玩了。那么《女神异闻录3 Reload》评价怎么样&#xff1f;Mac电脑怎…

web前端------弹性盒子

display属性&#xff0c;用于指定元素的盒子类型。 属性值flex&#xff0c;表示生成一个弹性容器&#xff0c;简称容器。 容器中每一个子元素都叫做项目。 我们知道了弹性盒子由容器和项目组成。 而CSS中提供了很多属性来实现弹性布局&#xff0c;按照作用范围的不同&#…

汇编笔记 01

小蒟蒻的汇编自学笔记&#xff0c;如有错误&#xff0c;望不吝赐教 文章目录 笔记编辑器&#xff0c;启动&#xff01;debug功能CS & IPmovaddsub汇编语言寄存器的英文全称中英对照表muldivandor 笔记 编辑器&#xff0c;启动&#xff01; 进入 debug 模式 debug功能 …

SpringBoot源码解读与原理分析(八)ApplicationContext

文章目录 3.1.2 ApplicationContext3.1.2.1 ApplicationContext根接口3.1.2.2 ConfigurableApplicationContext3.1.2.3 EnvironmentCapable3.1.2.4 MessageSource3.1.2.5 ApplicationEventPublisher3.1.2.6 ResourcePatternResolver3.1.2.7 AbstractApplicationContext3.1.2.8 …

vue前端RSA使用公钥进行加密,公钥进行解密

记录下RSA使用公钥进行加密&#xff0c;公钥进行解密&#xff1a; 背景&#xff1a;由于项目要求前后端进行数据加密传输&#xff0c;具体数据使用aes进行加密&#xff0c;aes密钥使用rsa进行加密&#xff0c;加密后的aes密钥放在请求头和响应头进行传输。这里实现的是前端vue…

入门指南|Chat GPT 的兴起:它如何改变数字营销格局?

随着数字营销的不断发展&#xff0c;支持数字营销的技术也在不断发展。OpenAI 的 ChatGPT 是一项备受关注的突破性工具。凭借其先进的自然语言处理能力&#xff0c;ChatGPT 已被证明是全球营销人员的宝贵资产。在这份入门指南中&#xff0c;我们将探讨Chat GPT对数字营销专家及…

【HarmonyOS应用开发】HTTP数据请求(十四)

文章末尾含相关内容源代码 一、概述 日常生活中我们使用应用程序看新闻、发送消息等&#xff0c;都需要连接到互联网&#xff0c;从服务端获取数据。例如&#xff0c;新闻应用可以从新闻服务器中获取最新的热点新闻&#xff0c;从而给用户打造更加丰富、更加实用的体验。 那么…