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中 ...
随机推荐
- 第14.7节 Python模拟浏览器访问实现http报文体压缩传输
一. 引言 在<第14.6节 Python模拟浏览器访问网页的实现代码>介绍了使用urllib包的request模块访问网页的方法.但上节特别说明http报文头Accept-Encodin ...
- autojs websocket 核心示例代码,云控技术
//初始化方法 function recordInit(scriptName){ //let ipInfoJson = getIP() // let ip = ipInfoJson.cip // le ...
- Java基础学习之流程控制语句(5)
目录 1.顺序结构 2.选择结构 2.1.if else结构 2.2.switch case结构 3.循环结构 3.1.while结构 3.2.do while结构 3.3.for结构 3.3.1.普 ...
- Scrum 冲刺 第二篇
Scrum 冲刺 第二篇 每日会议照片 昨天已完成工作 队员 昨日完成任务 黄梓浩 初步完成app项目架构搭建 黄清山 完成部分个人界面模块数据库的接口 邓富荣 完成部分后台首页模块数据库的接口 钟俊 ...
- js实现跳转的几种方式
1. window.open("url"); 2.用自定义函数 <script> function openWin(tag,obj) { obj.target=&quo ...
- Python 反序列化漏洞学习笔记
参考文章 一篇文章带你理解漏洞之 Python 反序列化漏洞 Python Pickle/CPickle 反序列化漏洞 Python反序列化安全问题 pickle反序列化初探 前言 上面看完,请忽略下 ...
- stringbuilder和stringbuffer速度比较
同样的代码,只改了类型,分别为stringbuilder和stringbuffer,只比较一下,执行引擎为hive. 当数据量为100000条,string builder耗时280秒,stringb ...
- hashmap底层:jdk1.8前后的改变
将hashmap和currenthashmap放一块进行比较,是因为二者的结构相差不多,只不过后者是线程安全的. 首先说hashmap,在jdk1.8之前,hashmap的存储结构是数组+链表的形式, ...
- Android原子操作——android_atomic_cmpxchg
网络给我们带来了很多方便,查阅我们目前认知范围外的道理.但是,凡事也要学会分辨,不然可能会误导你. 话说,最近的一个项目(Mercury-Project),接近尾声中.然而,在调试一个demo时,却遇 ...
- Spring Boot 最简单的解决跨域问题
跨域问题(CORS) CORS全称Cross-Origin Resource Sharing,意为跨域资源共享.当一个资源去访问另一个不同域名或者同域名不同端口的资源时,就会发出跨域请求.如果此时另一 ...