Redis缓存篇(二)淘汰机制:缓存满了怎么办?
上一讲提到,缓存的容量总是小于后端数据库的。随着业务系统的使用,缓存数据会撑满内存空间,该怎么处理呢?
本节我们来学习内存淘汰机制。在Redis 4.0之前有6种内存淘汰策略,之后又增加2种,一共8种,如下图所示:

- noeviction策略:内存空间达到maxmemory时,不会淘汰数据,有新写入时会返回错误。
- volatile-ttl策略:针对设置了过期时间的键值对,根据过期时间的先后进行修改,越早过期的越先被删除。
- volatile-random策略:在设置了过期时间的键值对中,进行随机删除。
- volatile-lru策略:使用LRU算法筛选设置了过期时间的键值对,进行删除。
- volatile-lfu策略:使用LFU算法筛选设置了过期时间的键值对,进行删除。
- allkeys-random策略:在所有键值对中随机选择并删除数据。
- allkeys-lru策略:使用LRU算法在所有数据中进行筛选并删除数据。
- allkeys-lfu策略:使用LFU算法在所有数据中进行筛选并删除数据。
对于TTL、Random比较好理解,下面学习一下LRU和LFU算法。
LRU算法
LRU算法,全称Least Recently Used。

其中MRU端指最近访问的数据;LRU端指最早访问的数据。
被访问的数据和新插入的数据会移到MRU端,空间满了后从LRU端删除。这样一来,最早访问的数据会逐渐被淘汰。
但LRU算法也有其缺点:
- 需要用链表管理所有缓存数据,带来额外的空间开销
- 大量数据被访问,就会带来很多链表移动操作,降低Redis性能
而Redis对其进行简化:
- Redis会记录每个数据的最近一次访问的时间戳(RedisObject中的lru字段)
- Redis第一次淘汰数据时,会随机选出N个数据,作为一个候选集合。
- 然后比较这N个数据的lru,把lru最小的从缓存中淘汰。
当再次淘汰数据时,会挑选数据放到第一次淘汰时的候选集合,要求小于候选集合中最小的lru值才能加入。
其中maxmemory-samples配置项:表示选出的个数N。可以通过以下命令进行设置:
CONFIG SET maxmemory-samples 100
LFU算法
LFU算法是在LRU策略基础上,为每个数据增加一个计数器,来统计这个数据的访问次数。
使用LFU策略筛选淘汰数据时,根据数据的访问次数进行筛选,把访问次数最低的数据淘汰。如果两个数据访问次数相同,再比较两个数据的访问时效性,把更久的数据淘汰。
如何实现
LFU也是使用RedisObject的lru字段来实现。
把24bit的lru字段拆分成两部分:
- ldt值:lru字段的前16bit,表示数据的访问时间戳;
- counter值:lru字段的后8bit,表示数据的访问次数;
当LFU策略淘汰数据时,Redis在候选集合中,根据lru字段的后8bit选择访问次数最小的数据进行淘汰。如果访问次数相同,再根据lru字段的前16bit值大小,选择更久的数据进行淘汰。
关于counter只有8bit(255)的问题
Redis并没有采用数据每被访问一次,就+1的规则,而是采用一个类似于随机+1的规则:
double r = (double)rand()/RAND_MAX;
...
double p = 1.0/(baseval*server.lfu_log_factor+1);
if (r < p) counter++;
通过设置 lfu_log_factor 配置项来控制计数器值增加的速度,避免counter很快到255。下图是 lfu_log_factor 设置不同值时,counter的增长情况:

总结
- 如何设置缓存空间大小:设置为总数据量的15%到30%,兼顾访问性能和内存空间开销。
- 优先使用allkeys-lru策略。如果业务数据中有明显的冷热数据区分,建议使用allkeys-lru策略。
- 如果业务数据访问频繁相关不大,没有明显的冷热数据区分,建议使用allkeys-random策略。
- 如果业务中有置顶的需要,可以使用volatile-lru策略,同时不给这些置顶数据设置过期时间。
参考资料
Redis缓存篇(二)淘汰机制:缓存满了怎么办?的更多相关文章
- Redis缓存篇(三)缓存污染
上一讲介绍了缓存满了,通过内存淘汰机制来淘汰掉数据.如果有的数据一直滞留在缓存中,但又没有应用使用,时间长了,就可能会占据大部分的缓存空间. 今天我们来学习一下缓存污染,以及如何解决缓存污染. 缓存污 ...
- Redis缓存篇(四)缓存异常
这一节,我们来学习一下缓存异常.缓存异常有四种类型,分别是缓存和数据库的数据不一致.缓存雪崩.缓存击穿和缓存穿透. 下面通过了解这四种缓存异常的原理和应对方法. 缓存和数据库的数据不一致 缓存和数据库 ...
- PHP+Redis 实例【二】页面缓存 新玩法
今天算是认识到博客园里的审查团队多内幕了,哈哈,贴个图玩下. 气死宝宝了. 进入主题! 今天就不写什么功能性的了,换下口味说下关于页面级的缓存,应该怎么做. 相信有很多小伙伴查了百度,甚至google ...
- Redis操作篇(二)
redis的发布与订阅,主从架构,哨兵架构,cluster集群 下载编译安装redis # 1. 下载redis wget http://download.redis.io/releases/redi ...
- 关于redis的几件小事(四)redis的过期策略以及内存淘汰机制
1.数据为什么会过期? 首先,要明白redis是用来做数据缓存的,不是用来做数据存储的(当然也可以当数据库用),所以数据时候过期的,过期的数据就不见了,过期主要有两种情况, ①在设置缓存数据时制定了过 ...
- MVC3缓存之一:使用页面缓存
MVC3缓存之一:使用页面缓存 在MVC3中要如果要启用页面缓存,在页面对应的Action前面加上一个OutputCache属性即可. 我们建一个Demo来测试一下,在此Demo中,在View的Hom ...
- Spring Boot 揭秘与实战(二) 数据缓存篇 - Redis Cache
文章目录 1. Redis Cache 集成 2. 源代码 本文,讲解 Spring Boot 如何集成 Redis Cache,实现缓存. 在阅读「Spring Boot 揭秘与实战(二) 数据缓存 ...
- Redis 的缓存淘汰机制(Eviction)
本文从源码层面分析了 redis 的缓存淘汰机制,并在文章末尾描述使用 Java 实现的思路,以供参考. 相关配置 为了适配用作缓存的场景,redis 支持缓存淘汰(eviction)并提供相应的了配 ...
- SpringBoot缓存篇Ⅱ --- 整合Redis以及序列化机制
一.Redis环境搭建 系统默认是使用ConcurrentMapCacheManager,然后获取和创建ConcurrentMapCache类型的缓存组件,再将数据保存在ConcurrentMap中 ...
随机推荐
- Python特殊序列\d能匹配哪些数字?
在缺省语言环境下,老猿对\d的匹配范围做了个测试,下面的数字包含半角数字.全角数字.中文数字,测试语句如下: >>> m=re.search(r'(\d*)(\D*)(\d*)',' ...
- PyQt(Python+Qt)学习随笔:QListWidget的addItem方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在QListWidget对象中,增加一个项的方法是调用addItem方法,addItem方法有2种重 ...
- Python爬虫学习遇到的问题
老猿在学习Python中爬虫知识时遇到了如下问题: 爬取网页内容后写入文件报错UnicodeEncodeError: 'gbk' codec can't encode的问题解决方案 urllib.re ...
- autojs websocket 核心示例代码,云控技术
//初始化方法 function recordInit(scriptName){ //let ipInfoJson = getIP() // let ip = ipInfoJson.cip // le ...
- 当你在浏览器输入一个网址(如http://www.taobao.com),按回车之后发生了什么?
首先你输入了一个网址并按下了回车,这个时候浏览器会根据这个URL去查找其对应的IP,具体过程如下: 首先是查找浏览器缓存,浏览器会保存一段时间你之前访问过的一些网址的DNS信息,不同浏览器保存的时常不 ...
- neo4j数据库数据转移,从阿里云转移到windows服务器
1.从阿里云迁移neo4j时需停掉neo4j数据库,在neo4j的bin目录下输入 ./neo4j stop 2.将数据备份到一个文件中 ./neo4j-admin dump --database=g ...
- JAVA_数据类型介绍与基本数据类型之间的运算规则
基本数据类型 整型: byte.short.int.long java 的整型常量默认为int型,在java程序中变量通常声明为int型,除非不足以表示较大的数才用long,而在声明long型常量必须 ...
- BJWC2011 禁忌
题目链接 题解 多模式匹配首先建 AC 自动机,看到 \(len \le 10^9\) 想到矩阵乘法优化. 朴素 DP 关于分割的最大值,可以贪心,只要走到一个能匹配串的点立刻返回根继续匹配就行,一定 ...
- 六、TestNG传递参数1
TestNG可以通过testng.xml和Data Providers向测试方法传递参数 利用testNG.xml传递参数 1-创建一个TestNG测试类 其中 parameters = {" ...
- jenkins+ant+jmeter实现自动化集成(详解)
jenkins+ant+jmeter实现自动化集成 for window 一.jmeter 1.jmeter安装 二.ant 1.ant安装 三.ant运行 jmeter脚本 1.配置 四.jenki ...