1.Redis内存满了怎么办
2.往redis里写的数据是怎么没了的?它如何删除的?
3.redis缓存淘汰策略
4.总结
1.Redis内存满了怎么办
redis是我们每天都在开发和使用的一个工具,但是我们在使用它的时候,有仔细关注过它的默认占用内存是多少吗?以及如何修改呢?
1.1Redis默认内存多少?怎么查看?如何修改?
我们打开redis的配置文件,搜索一下maxmemory,会发现这么一行代码:
可以看出,把这个设置打开,并且在
设置为 0 ,或者不设置这个字段,表示不限制 Redis 内存使用。
1.2生产上如何配置redis占用内存的大小?
一般推荐Redis设置内存为最大物理内存的四分之三。
1.3 如果打满了redis的使用内存会怎么样?
我们设置一下redis的缓存使用上限,我们设置为10个byte,再设置一个值,看看。
因为这个key没有加上过期时间,就会导致maxmemory异常,为了避免这个情况,我们要有缓存淘汰策略。
2.往redis里写的数据是怎么没了的?它如何删除的?
我们先来思考一个问题,在什么都不配置的情况下,redis的一个键如果是设置了过期时间的,到期之后,是不是马上就会从redis中被删除呢?
答案:如果不配置缓存淘汰策略,redis是不会把过期的key从内存中删除出去的,虽然看起来这个key已经查不到了:
让我们来思考一下,如果要删除过期的key,能有什么策略?常规能想到的有:
1)立即删除
redis一直遍历着所有被设置了过期时间的key,来检测是否已经到了过期时间,然后对它进行删除。
立即删除能保证内存中数据的最大新鲜度,因为它能保证键值对在过期后马上被删除,所占用的内存也会被释放,但这样对cpu是不友好的,因为遍历/删除都会占用cpu的时间,如果刚好碰倒cpu很忙的时候,就会给cpu造成额外的压力,产生极大的性能消耗,同时也会影响读取操作。
总结:对内存友好,对cpu不友好。
2)惰性删除
数据到达过期时间,不做处理,等下次访问该数据的时候
如果未过期,返回该数据
如果过期了,就删除这个key,返回不存在
惰性删除的缺点是,它对内存极其不友好。
如果这个key已经过期,而且是一个大key,如果这个key不被访问,就会一直存在于数据库中,那么它永远也不会被删除。我们甚至可以将这种情况视为内存泄漏-无用的垃圾数据占用了大量的内存,而服务器却不去释放他们,对于非常依赖内存的redis而言,肯定不是一个好消息。
3)定期删除策略
定期删除策略是上面两种方式的折中处理:
每隔一段时间执行一次删除过期key操作,并通过限制删除操作执行时长和频率来减少删除操作对cpu时间都的影响(有点像jvm虚拟机中能控制吞吐量的Parallel垃圾收集器)。定期轮询redis库中的时效性数据,采用随机抽取的策略,抽到过期的key就进行删除。
特点1:cpu性能占用设置有峰值,检测频率和自行控制
特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
缺点:
1)定期删除执行的时长和频率很难界定,如果执行地太频繁,或者执行时间太长,这种策略就会变为立即删除策略,消耗cpu,如果执行地太不频繁,又会像惰性删除策略一样,出现浪费内存的情况。
2)会有一直都没被抽查到的key(漏网之鱼)的存在。
这时,为了解决这些问题,我们的redis缓存淘汰策略就登场了!
3.redis缓存淘汰策略
我们打开redis的配置文件,搜索 'maxmemory-policy'
就会发现,默认的缓存淘汰策略就是什么都不淘汰。
redis的缓存淘汰策略有哪些:
1)noeviction: 不会驱逐任何key
2)allkeys-lru: 对所有key使用LRU算法进行删除
3)volatile-lru: 对所有设置了过期时间的key使用LRU算法进行删除
4)allkeys-random: 对所有key随机删除
5)volatile-random: 对所有设置了过期时间的key随机删除
6)volatile-ttl: 删除马上要过期的key
7)allkeys-lfu: 对所有key使用LFU算法进行删除
8)volatile-lfu: 对所有设置了过期时间的key使用LFU算法进行删除
上面出现了两个名词,LRU和LFU,我们先来解释一下这两个词语的意思:
LRU:
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法。
LFU:
即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页。
一个强调的是使用频率,一个强调的是最近未使用。
我们可以先把上面的redis缓存淘汰策略进行归类:
1)是对所有key,还是对设置了过期时间的key
2)是随机删除,全部删除,还是用LRU或者LFU删除。
两个维度和四个方面,获得了八种结果。
那我们平时使用哪个呢?
如果分为一般的热数据和冷数据,那么我们都推荐使用 allkeys-lru 策略,其中一部分key经常被读写,如果在不确定业务的情况下,allkeys-lru是一个比较好的选择(被淘汰的冷数据如果又要再次被访问,则可以通过业务逻辑代码重新读入缓存中)。
如果各个key访问的频率差不多,则可以使用 allkeys-random 策略, 即读写所有元素的概率差不多。
如果要让redis根据ttl来筛选要删除的key,请使用volatile-ttl 策略。
volatile-lru 和 volatile-random 策略应用场景是: 既有要过期的key,又有持久key的实例中。 对于这类场景,我们一般使用两个单独的redis。
4.总结
今天我们学习了redis缓存的淘汰策略,注意一开始redis服务占用的缓存大小和淘汰策略都是没有配置过的,而且很少的公司会去配置,如果公司redis场景用的多,我们就要注意一下这方面了!