Redis中共有八种内存淘汰策略:
- Volatile-lru: 设置了过期时间的Key使用了LRU算法淘汰;
- Allkeys-lru: 所有key使用LRU算法;
- Volatile-lfu: 设置了过期时间的key使用了LFU算法淘汰;
- Allkeys-lfu: 所有key使用了LFU算法淘汰;
- Volatile-random: 设置了过期时间的key使用随机淘汰;
- Allkeys-random: 所有key使用随机淘汰;
- Volatile-ttl: 设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰;
- Noeviction: 默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错,(如set,ipush等),只读操作如get命令可以正常执行.
LRU、LFU和volatile-ttl都是近似随机算法;
在缓存的内存淘汰策略中有FIFO、LRU、LFU三种,其中LRU和LFU是Redis在使用的.
FIFO是最简单的淘汰策略,遵循先进先出的原则.
LRU算法:表示最近最少使用,该算法根据数据的历史记录来进行淘汰数据,其核心思想是”最近被使用过,那么将来被访问的记录也更高”.
LRU算法的常见实现方式为链表,新数据放在链表头,链表中的数据被访问就移动到链头,链表满的时候从链表尾部移除数据.
而Redis中使用的是近似LRU算法,为什么说是近似呢?Redis中是随机采样5个Key,然后从中选择访问时间最早的Key进行淘汰,因此当采样Key的数量与Redis库中Key的数量越接近,淘汰的规则就越接近LRU算法.官方推荐采样5个Key就够了,最多不超过10个,越大就越消耗CPU的资源.
但在LRU算法下,Redis会为每个Key新增一个3字节的内存空间来存储Key的访问时间.
LFU算法表示最不经常使用,它是根据数据的历史访问频率来淘汰数据,其核心思想是”如果数据过去被访问多次,那么将来被访问的频率也更高”.
LFU算法反映了一个Key的热度情况,不会因LRU算法的偶尔一次被访问被误认为是热点数据.
LFU算法的常见实现方式为链表:新数据放在链表尾部,链表中的数据按照被访问次数降序排列,访问次数相同的按最近访问时间降序排列,链表满的时候从链表尾部移除数据.
过期删除策略
Redis内存没有被占满时,过期的Key是如何从内存中删除的.
在Redis中过期的Key不会立刻从内存中删除,而是会同时以下面两种策略进行删除
- 惰性删除: 当Key被访问时检查该Key的过期时间,若已过期则删除;已过期未被访问的数据仍保存在内存中,消耗内存资源;
- 定期删除: 每隔一段时间,随机检查设置了过期的Key并删除已过期的Key;维护定时器消耗CPU资源;
Redis每10s进行一次过期扫描:
- 随机取20个设置了过期策略的Key;
- 检查20个Key中过期时间中已过期的Key并删除;
- 如果有超过25%的Key已过期则重复第一步;
这种循环随机操作会持续到过期Key可能仅占全部的Key25%以下,并且为了保证不会出现循环过多的情况,默认扫描时间不会超过25ms;