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 多次访问 的评价标准最终形成对键重要性的评判。
相关文章:
Redis中内存淘汰算法实现
Redis中内存淘汰算法实现 Redis的maxmemory支持的内存淘汰机制使得其成为一种有效的缓存方案,成为memcached的有效替代方案。 当内存达到maxmemory后,Redis会按照maxmemory-policy启动淘汰策略。 Redis 3.0中已有淘汰机制: noevictionall…...
人工智能(pytorch)搭建模型23-pytorch搭建生成对抗网络(GAN):手写数字生成的项目应用
大家好,我是微学AI,今天给大家介绍一下人工智能(pytorch)搭建模型23-pytorch搭建生成对抗网络(GAN):手写数字生成的项目应用。生成对抗网络(GAN)是一种强大的生成模型,在手写数字生成方面具有广泛的应用前景。通过生成…...
解决使用Springboot jpa update数据时报错Executing an update:delete query
解决org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query 使用的Springboot jpa ,使用原生SQL方法实现数据更新时&…...
OpenCV-32 膨胀操作
膨胀是与腐蚀相反的操作,基本原理是只要保证卷积核的锚点是非0值,周边无论是0还是非0值,都变为0。 使用API---dilate(img, kernel, iterationms 1) 示例代码如下: import cv2 imp…...
7.0 Zookeeper 客户端基础命令使用
zookeeper 命令用于在 zookeeper 服务上执行操作。 首先执行命令,打开新的 session 会话,进入终端。 $ sh zkCli.sh 下面开始讲解基本常用命令使用,其中 acl 权限内容在后面章节详细阐述。 ls 命令 ls 命令用于查看某个路径下目录列表。…...
使用virtualenv管理python环境
Windows配置virtualenv 安装 pip install virtualenv virtualenvwrapper virtualenvwrapper-win设置WORK_HOME环境变量 在系统path变量中添加虚拟环境目录:键WORKON_HOMEC:dev\Envs 修改windows环境下mkvirtualenv.bat文件,配置虚拟环境根目录地址 配…...
Linux---线程
线程概念 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列” 一切进程至少都有一个执行线程 线程在进程内部运行,本质是在进程地址空间内运行 在Linux系统中,在CPU眼中…...
Linux 命令行速查表
Linux 命令行速查表 Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能…...
强化学习 | 基于 Q-Learning 算法解决 Treasure on Right 游戏
Hi,大家好,我是半亩花海。在本篇技术博客中,我们将探讨如何使用 Q-Learning 算法来解决 Treasure on Right 游戏,实现一个简单的强化学习。 一、游戏背景 Treasure on Right 游戏——一个简单的命令行寻宝游戏,是一个…...
计算机网络-无线通信技术与原理
一般我们网络工程师接触比较多的是交换机、路由器,很少涉及到WiFi和无线设置,但是呢在实际工作中一般企业也是有这些需求的,这就需要我们对于无线的一些基本配置也要有独立部署能力,今天来简单了解一下。 一、无线网络基础 1.1 无…...
机器学习 | 揭示EM算法和马尔可夫链的实际应用
目录 初识EM算法 马尔可夫链 HMM模型基础 HMM模型使用 初识EM算法 EM算法是一种求解含有隐变量的概率模型参数的迭代算法。该算法通过交替进行两个步骤:E步骤和M步骤,从而不断逼近模型的最优参数值。EM算法也称期望最大化算法,它是一个基…...
回归预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测
回归预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测 目录 回归预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测(完整源码…...
基于java+springboot+vue实现的房屋租赁管理系统(文末源码+Lw)23-142
第1章 绪论 房屋租赁管理系统管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、字典管理、租房房源管理、租房评价管理、房源租赁管理、租房预约管理、论坛管理、公告管理、投诉建议管理、用户管理、租房合同管理、管理员管理。用户的功能等。该系统采用了My…...
ubuntu20安装mongodb
方法一:直接安装(命令是直接从mongo官网Install MongoDB Community Edition on Ubuntu — MongoDB Manual复制的) cat /etc/lsb-release sudo apt-get install -y gnupg curl curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \sudo gp…...
java面试题:MySQL中的各种JOIN的区别
表关联是频率非常高的一种数据库操作,在MySQL中,这种JOIN操作有很多类型,包括内联接、左外连接、右外连接等等,而每种连接的含义都不一样,如果死记硬背,不仅很难记住,而且也容易搞混淆ÿ…...
C语言数组与扫雷游戏实现(详解)
扫雷游戏的功能说明 使⽤控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩或者退出游戏扫雷的棋盘是9*9的格子默认随机布置10个雷可以排查雷 ◦ 如果位置不是雷,就显示周围有几个雷 ◦ 如果位置是雷,就炸死游戏结束 ◦ 把除10个雷之外的所有雷都找出来,排雷成功,游戏结…...
C#调用WechatOCR.exe实现本地OCR文字识别
最近遇到一个需求:有大量的扫描件需要还原为可编辑的文本,很显然需要用到图片OCR识别为文字技术。本来以为这个技术很普遍的,结果用了几个开源库,效果不理想。后来,用了取巧的方法,直接使用了WX的OCR识别模…...
ComfyUI 学习笔记
目录 ComfyUI 入门教程 什么是ComfyUI? windows安装教程: 组件技巧学习 ComfyUI 入门教程 老V带你学comfyUI-基础入门 - 知乎 什么是ComfyUI? ComfyUI 是一个基于节点的 GUI,用于Stable Diffusion。你可以通过将不同的no…...
基于Linux的HTTP代理服务器搭建与配置实战
在数字化世界中,HTTP代理服务器扮演着至关重要的角色,它们能够帮助我们管理网络请求、提高访问速度,甚至在某些情况下还能保护我们的隐私。而Linux系统,凭借其强大的功能和灵活性,成为了搭建HTTP代理服务器的理想选择。…...
创建一个Vue项目(含npm install卡住不动的解决)
目录 1 安装Node.js 2 使用命令提示符窗口创建Vue 2.1 打开命令提示符窗口 2.2 初始Vue项目 2.2.1 npm init vuelatest 2.2.2 npm install 3 运行Vue项目 3.1 命令提示符窗口 3.2 VSCode运行项目 1 安装Node.js 可以看我的这篇文章《Node.js的安装》 2 使用命令提示…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
