Redis 淘汰策略
Redis已经设置了过期时间也就是TTL,那么键过期了不就是已经删除了吗?为什么还存在淘汰策略呢?
这要从Redis的过期策略来聊起
过期策略分为两种
- 一个是定时删除
- 还有一个是惰性删除
先来看下定时删除,就是Redis
会将每个设置了过期时间的key,放入到一个独立的字典中,然后会定期遍历这个字典来删除到期的key。除了定时遍历之外,它还会使用惰性策略来删除过期的 key。
所谓惰性策略就是在客户端访问这个 key
的时候,Redis 对 key 的过期时间进行检查,如果过期了就立即删除。
说白了,定时删除是集中处理,而惰性删除是零散处理。
因为Redis不可能遍历这个字典中所有的key
举个例子:假如 Redis 中存了几十万个 key,每隔一段时间就会遍历所有的设置过期时间的Key,就会给CPU带来很大的负载。
所以Redis默认会每秒进行十次过期扫描,也就是100MS一次,过期扫描不会遍历过期字典中所有的Key,而是采用了一种简单的贪心策略
什么是贪心策略
- 就是从过期字典中随机20个key
- 删除这 20 个 key 中已经过期的 key;
- 如果过期的 key 比率超过 1/4,那就重复步骤 1;
同时,为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms。
如何配置定期删除执行的时间间隔呢?
Redis的定时任务默认是1s执行10次,也就是100ms一次,值越大说明刷新频率越快,对Redis性能损耗也越大,如果要修改这个值,可以在redis.conf
中修改hz
的值。
可以看到在 redis.conf
这个文件中,默认为10,提高它的值将会占用更多的cpu,当然,相应的Redis将会更快的处理,同时到期的许多key,以及更精确的去处理超时。hz
的取值范围是1~500,通常不建议超过100,只有在请求延时非常低的情况下可以将值提升到100。
介绍了过期策略,就知道为什么要使用淘汰策略了吧
淘汰策略
如果说定期删除漏掉了很多过期的 key,后期也没及时去查过期key,也就是没走惰性删除,此时大量过期key堆积在内存里,导致Redis内存块耗尽了,这时候就要使用 Redis 的内存淘汰机制解决这个问题,也就是当前已使用内存超过maxmemory
限定时,触发内存淘汰机制
这个值是在 redis.conf
文件中设置的,如下图所示:
内存淘汰策略有这么几种
-
noeviction:当内存使用超过配置的时候会返回错误,但是不会驱逐任何键
-
allkeys-lru:加入键的时候,如果超过限制,首先通过LRU算法驱逐最久没有使用的键
-
volatile-lru:加入键的时候,如果超过限制,首先从设置了过期时间的键集合中驱逐最久没有使用的键
-
allkeys-random:加入键的时候如果过限,从所有key随机删除。我们的应用对于缓存key的访问概率相等,则可以使用这个策略。
-
volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐
-
volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键。这种策略使得我们可以向Redis提示哪些key更适合被驱逐
-
volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
-
allkeys-lfu:从所有键中驱逐使用频率最少的键
这就是内存淘汰策略的几种模式在Redis中的用途
接下来看下LRU
和LFU
的实现方式
先来看下LRU的实现方式
- 新数据插入到链表头部;
- 每当缓存命中(也就是缓存数据被访问)的时候,就会将数据移动到链表头部
- 当链表满的时候呢,将链表尾部的数据丢弃
简单来说就是淘汰长时间没有被使用的键,以时间作为参考
我们再来看下LFU他的实现方式是什么样的
- 新加入数据插入到队列尾部
- 队列中的数据被访问后,引用次数增加,队列重新排序
- 当需要淘汰数据时,将已经排序的列表最后的数据块删除
简单来说就是淘汰一定时间内被访问次数最少的键,以次数作为参考
这就是有关于淘汰策略
了解更多可扫码关注公众号