聊聊 Redis 内存淘汰策略
这一期咱们一起来看看 Redis 的内存淘汰策略~
为什么要有内存淘汰机制
大家都知道 Redis 中的键会设置过期时间,当到达过期时间时会通过一定策略清除对应 key,但是 redis 内存是由上限的,当达到内存上限时,就要通过一定策略淘汰掉相应 kv 键值对。
Redis 内存上限
maxmemory 配置选项使用来配置 Redis 的存储数据所能使用的最大内存限制。可以通过在内置文件redis.conf中配置,也可在Redis运行时通过命令CONFIG SET来配置。例如,我们要配置内存上限是100M的Redis缓存,那么我们可以在 redis.conf 配置如下:
maxmemory 100mb 复制代码
设置 maxmemory 为 0 表示没有内存限制。在 64-bit 系统中,默认是 0 无限制,但是在 32-bit 系统中默认是 3GB。
当存储数据达到限制时,Redis 会根据情形选择不同策略,或者返回errors(这样会导致浪费更多的内存),或者清除一些旧数据回收内存来添加新数据。
Redis 内存淘汰策略
- noenviction:不清除数据,只是返回错误,这样会导致浪费掉更多的内存,对大多数写命令(DEL 命令和其他的少数命令例外)
- allkeys-lru:从所有的数据集中挑选最近最少使用的数据淘汰,以供新数据使用
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰,以供新数据使用
- allkeys-random:从所有数据集中任意选择数据淘汰,以供新数据使用
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰,以供新数据使用
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰,以供新数据使用
- volatile-lfu:从所有配置了过期时间的键中淘汰使用频率最少的键
- allkeys-lfu:从所有键中淘汰使用频率最少的键
回收的过程
理解回收过程是运作流程非常的重要,回收过程如下:
- 一个客户端运行一个新命令,添加了新数据。
- Redis检查内存使用情况,如果大于maxmemory限制,根据策略来回收键。
- 一个新的命令被执行,如此等等。
我们添加数据时通过检查,然后回收键以返回到限制以下,来连续不断的穿越内存限制的边界。
如果一个命令导致大量的内存被占用(比如一个很大的集合保存到一个新的键),那么内存限制很快就会被这个明显的内存量所超越。
近似LRU算法
Redis的LRU算法不是一个严格的LRU实现。这意味着Redis不能选择最佳候选键来回收,也就是最久未被访问的那些键。相反,Redis 会尝试执行一个近似的LRU算法,通过采样一小部分键,然后在采样键中回收最适合(拥有最久访问时间)的那个。
然而,从Redis3.0开始,算法被改进为维护一个回收候选键池。这改善了算法的性能,使得更接近于真实的LRU算法的行为。Redis的LRU算法有一点很重要,你可以调整算法的精度,通过改变每次回收时检查的采样数量。
这个参数可以通过如下配置指令:
maxmemory-samples 5 复制代码
Redis没有使用真实的LRU实现的原因,是因为这会消耗更多的内存。然而,近似值对使用Redis的应用来说基本上也是等价的。
LFU
LFU (Least frequently used) 最不经常使用算法。而 LRU 是最近最少使用算法。
从 Redis 4.0 开始,可以使用 LFU 过期策略。这种模式在某些情况下可能会更好(提供更好的命中率/未命中率),因为使用 LFU Redis 会尝试跟踪项目的访问频率,因此很少使用的项目会被淘汰,而经常使用的项目有更高的机会留在内存中。
那为什么会出现 LFU 算法那?大家请看下面的场景:
A - A - A - - - A - A -A - - - B - - - - B - - B - - - - - - B 复制代码
如果是 LRU 算法 那么会淘汰 A,因为 B 是最近使用的,但是很明显 A 的使用频率是最高的,理应留下 A,所以 LFU 算法应运而生。(淘汰最少使用的 key)
LFU 把原来的 key 对象的内部时钟的24位分成两部分,前16位还代表时钟,后8位代表一个计数器, 称为Morris 计数器。后8位表示当前key对象的访问频率,8位只能代表255,但是 redis 并没有采用线性上升的方式,而是通过一个复杂的公式,通过配置两个参数来调整数据的递增速度。
下图从左到右表示key的命中次数,从上到下表示影响因子,在影响因子为100的条件下,经过10M次命中才能把后8位值加满到255.
factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits |
---|---|---|---|---|---|
0 | 104 | 255 | 255 | 255 | 255 |
1 | 18 | 49 | 255 | 255 | 255 |
10 | 10 | 18 | 142 | 255 | 255 |
100 | 8 | 11 | 49 | 143 | 255 |
这个参数是可配置的的,通过这个:
lfu-log-factor 10 复制代码
上说的是计数器的增长,那么什么情况削减那?
默认是 如果一个 key 每一分钟没使用,Morris 计数器 就削减 1. 这个也可以通过下面进行配置:
lfu-decay-time 1 复制代码
有个问题就是,新的 key 怎么办,岂不是上来就被淘汰?
为了避免这种问题 Redis 默认情况下新分配的key的后8位计数器的值为5,防止因为访问频率过低而直接被删除。
总结
Redis 为了避免内存超出容量,使用特定的内存淘汰策略来释放内存,主要思想是 LRU 和 Redis 4.0 推出的 LFU 算法。LRU 是最近最少使用算法,LFU 是最少使用算法。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
前端之变(五):王者归来
本周继续就前端之变阐述自己的思考。 这是本系列的第五篇,前四篇为: 前端之变(一): 技术的变与不变 前端之变(二): "不变"的前端 前端之变(三):变革与突破 前端之变(三):进击的前端 前面几篇文章我已经分析过前端的变化了。豪无疑问,前端的变化是"质变"而非"量变",它不是递进式的出现一个新的技术语言或框架,从根本上说它是一种模式颠覆性的取代另一种模式。 本篇我就来探讨与分析一下,究竟是谁给前端带来了如此巨大的改变,前端这些年究竟发生了什么事情? 我还是从前端的发展历史开始说起吧. 前端发展史 上面这个图用时间线的方式浓缩的讲述了前端重要技术的一个发展史。这个图中有几个比较重要的时间点: 2006年 JQuery发布 2008年 Chrome&V8发布 2009年 NodeJS发布,同年ES5发布 2012年 Typescript发布 2013年 React发布 2014年 Vue发布 这几个节点是值得参考的时间点。 如同我在前面的文章所阐述的,JQuery与React,Vue完全不能类比。 JQuery是『前』前端时代最有名的框架,而React与Vue则是『后』前端时代...
- 下一篇
禅道自动化测试框架 ZTF 发布 2.4 版本,增加测试步骤自动提取功能
大家好,禅道自动化测试框架2.4版本发布,支持在脚本的任意地方编写测试步骤和期待结果,并提供了一个extract命令用于提取这些信息。 ZTF是禅道团队自研的自动化测试框架,支持与禅道无缝集成,可将禅道用例和测试脚本进行同步,将执行结果自动提交到禅道并生成测试报告,执行失败的用例可通过命令在禅道中创建Bug。ZTF自动化测试框架实现了与Jenkins持续集成功能的打通。用户发起Jenkins构建后,通过ZTF调度执行测试脚本,结束后把单元和功能测试的结果回传给禅道,二者合作打通持续集成的闭环。 欢迎大家下载试用,并提出宝贵建议。 一、更新记录 支持在脚本的任意地方编写测试步骤和期待结果; 新增extract命令,用于提取测试步骤和期待结果; 修复了一些小的问题。 二、下载地址 ztf-win64-2.4.zip ztf-win32-2.4.zip ztf-linux-2.4.tar.gz ztf-mac-2.4.zip 项目源代码(zip) GitHub项目首页 三、帮助文档 Jenkins持续集成文档 自动化测试文档 单元测试文档 四、新功能界面展示 从代码中提取测试步骤: 1. 示...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS关闭SELinux安全模块
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Hadoop3单机部署,实现最简伪集群