key值过期策略
为什么Redis要设置key值过期策略
Redis提供了过期策略,就是某个时刻Redis就会将某些key值清除。这个操作甚至导致了我们redis可能发生击穿与雪崩的后果。那么为什么redis一定要设置这种危险的策略呢?
我们知道Redis是基于内存的非关系型数据库。既然基于内存,所以可知受到内存容量的限制,Redis中能够存储的数据量不会太大,所以可以为redis中的数据设置过期时间,到期后就可以按照设置的机制对这些过期的数据进行删除,从而腾出空间来存放接下来需要存储的新的数据。
我们会发现,在mysql这种关系型数据库的中,InnoDB也提供了缓存机制,同时也需要定时的去刷盘,其道理都是一样的——受制于内存大小。
过期策略
定时过期
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;
而之所以可以实现定时清理,其原理是redis 默认是每隔固定的时间就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。
那我们就不难意识到一个问题。当redis中的数据逐渐增多,我们就需要浪费大量的CPU去检测这些key过没过期。注意:大部分的key在检测的时候都没有过期。也就是随意一个key值都会被这个CPU检测无数次后才能被成功清除。
因此,这个模式的缺点就是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性过期
只有当访问一个key时,才会判断该key是否已过期,过期则清除。
假设redis记录了一个token的有效期。当访问不到该值时,则表示token过期,顺带清理该redis的key。
该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期
可以发现上面的两种过期策略,要么极度消耗CPU,要么可能会造成内存泄漏。那么定期过期模式就是上面两种机制的折中方案。在开启惰性过期的同时,通过调整定时扫描的时间间隔,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
内存淘汰策略
为什么有内存淘汰策略
我们知道,仅仅有key的过期策略,并不能一定保证redis的内存一定是够用。如果redis的数据达到了内存峰值时,就需要触发内存淘汰策略,来处理需要新写入且需要申请额外空间的数据。我们很容易想到,这种万不得已的处理情况,线程池的任务淘汰机制也十分类似。
具体的淘汰机制
noeviction | 默认策略,对于写请求直接返回错误,不进行淘汰 |
allkeys-lru | 从所有的key中使用近似LRU算法进行淘汰 |
volatile-lru | 从设置了过期时间的key中使用近似LRU算法进行淘汰。 |
allkeys-random | 从所有的key中随机淘汰 |
volatile-random | 从设置了过期时间的key中随机淘汰 |
volatile-ttl | 在设置了过期时间的key中根据key的过期时间进行淘汰,越早过期的越优先被淘汰。 |
allkeys-lfu | 从所有的key中使用近似LFU算法进行淘汰。从Redis4.0开始支持。 |
volatile-lfu | 从设置了过期时间的key中使用近似LFU算法进行淘汰。从Redis4.0开始支持。 |
内存淘汰用于redis占满整个内存时的被破策略。一般情况下要尽可能避免这种情况。可以通过调整过期策略,或是扩大内存的方式来解决这个问题。