本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
前言
Redis作为常用的NoSQL数据库,通常是把数据存储在内存中,但是机器的内存不是无限大的,因而当越来越多的数据存储到Redis中,内存不够用时,就需要回收内存了。Redis中的内存回收主要来自于以下两个方面:
- 过期策略:删除过期时间的
key; - 淘汰策略:内存使用达到了设定的
maxmemeory上限时触发内存淘汰策略
Redis 过期策略
过期策略有三种,分别是定时过期、惰性删除和定时扫描删除。
定时过期
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期数据,对内存很友好,但是这样会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性删除
只有当访问一个key时才去判断这个key是否已经过期,若过期则进行清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。若是内存中存在着大量的没有被访问过的过期key,于是内存就会被大量占用,影响机器性能。
定时扫描删除
每隔一段时间,Redis会开启一个线程去扫描若干数据库中的expires字典中一定数量的key,并清除其中已经过期的key。该策略是前两种策略的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定时耗,可以使得CPU和内存资源达到最优的平衡效果。
Redis中同时使用了惰性删除和定时扫描这两种过期策略
惰性删除流程:
- 在进行
get或者set/setex/setnx等操作时,先检测key是否过期; - 若过期,则删除
key,然后执行相应操作; - 若否,则直接执行相应操作;
定时扫描删除:
- 遍历每个数据库(
redis.conf中配置的database数量,默认16); - 检查当前库中的指定个数个
key(默认每个库检查20个key,相当于循环执行20次); - 如果一个库中没有一个
key设置了过期时间,直接执行下一个库的遍历; - 随机获取一个设置了过期时间的
key,检查该key是否过期,若过期,则直接删除; - 判断定时扫描操作是否已经达到指定时长,若已经达到,直接退出定期删除;
- 对于定时扫描删除,在
Redis中有一个全局变量current_db来记录下一个将要遍历的库。假设现在有16个库,我们这一次定时扫描遍历了10个库,那么此时的current_db就是11,下一次定时扫描将直接从第11个库开始遍历。假如current_db等于15,那么下次遍历将再从0号库开始(此时current_db=0);
Redis数据淘汰策略
当内存达到设定的maxmemory上限时,Redis开启内存淘汰策略以清除旧数据保证新数据的存入。Redis默认使用近似LRU算法来进行内存淘汰。
缓存清理配置
在redis.conf文件中,我们可以通过配置maxmemory的大小来设置Redis存放数据的内存大小。一旦Redis中存储的数据大小超过maxmemory,Redis就会使用相应策略来淘汰数据以保证新数据可以存入。
这里需要注意的是,对于64位的机器,如果maxmemory设置为0,那么就默认不限制内存的使用,直到耗尽机器中所有的内存为止;,但是对于32位的机器,有一个隐式的限制,不超过3GB。
Redis 数据淘汰策略
当Redis中存储数据大小达到maxmemory时,此时就会开启数据淘汰策略。Redis共提供了八种淘汰策略,大致分为三类:
第一类:
- noeviction:当内存不足以容纳新写入的数据时,新写入操作会直接报错;
第二类:
- allkeys-lru:使用
LRU算法,移除Redis内存中最近最少使用的key; - allkeys-lfu:使用
LFU算法,移除Redis内存中最不经常使用的key; - allkeys-random:随机删除某个
key;
第三类:
- volatile-lru:在设置了过期时间的键中使用
LRU算法移除最近最少使用的key; - volatile-lfu:在设置了过期时间的键中使用
LFU算法移除最不经常使用的key - volatile-random:在设置了过期时间的键中随机移除某个
key; - volatile-ttl:在设置了过期时间的键中,优先移除过期时间最长的那个
key;
Redis中默认淘汰策略为noeviction。
缓存清除流程
- 客户端执行写入请求;
Redis Server接收到写入操作后,检查maxmemory的限制,如果超过了限制,那么根据对应的数据清理策略来清理掉部分数据;- 写入操作完成执行
总结
要注意区分Redis的过期策略和淘汰策略其各自的作用。
- 过期策略是针对设置了过期时间的
key,目的是为了回收它们所占用的空间,保持Redis正常运行,过期策略为惰性策略+定时扫描策略 - 淘汰策略是针对
Redis内存不足时,该如何处理旧的数据从而使得新数据得以存入