Redis过期策略与淘汰策略
参加面试连过期策略和淘汰策略概念都傻傻分不清楚
参加了一个面试,面试官问我过期策略有几种,我TM给人说了几种淘汰策略,面试官一脸无辜,我还感觉良好
开始正文吧:
1、过期策略(过期键的删除策略):redis使用过程中,很多时候我们会设置一个过期时间,那么当时间到了的时候,数据会立马删除吗?有可能会,也有可能不会,这就跟过期策略有关了,就是看看redis是如何知道过期的,并且进行的删除。
先说结论:有三种
第一种:定时删除
在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
优点:对内存最友好的。可以及时释放键所占用的内存。
缺点:对 CPU 不友好。特别在过期键比较多的情况下,删除过期键会占用相当一部分 CPU 时间。同时在内存不紧张,CPU 紧张的情况下,将 CPU 用在删除和当前任务不想关的过期键上,
无疑会对服务器响应时间和吞吐量造成影响。
第二种:惰性删除
放任键过期不管,但是每次从键空间中读写键时,都会检查取得的键是否过期。如果过期就删除该删,否则就返回该键。(PS:键空间是一个保存了数据库所有键值对的数据结构)
优点:对 CPU 最友好。只有在操作的时候进行过期检查,删除的目标仅限于当前需要处理的键,不会在删除其他无关本次操作的过期键上花费任何 CPU 时间。
缺点:对内存不友好。这个十分容易理解了,键过期了,但因为一直没有被访问到,所以一直保留着(除非手动执行 flushdb 操来于清空当前数据库中的所有 key。),相当于内存泄漏。
第三种:定期删除
每隔一段时间,程序就对数据库进行检查,删除里面的过期键。至于要删除多少过期键,以及检查多少数据库,则有算法决定。该策略是上述两种策略的折中方案,需要通过实际情况,
来设置删除操作的执行时长和频率。明白了过期键的删除策略后,那 redis 服务器又是采用什么策略来删除过期键的呢?实际上,Redis 服务器使用的是惰性删除和定期删除两种策略,
通过配合使用,服务器可以很好的平衡 CPU 和内存。其中惰性删除为 redis 服务器内置策略。而定期删除可以通过以下两种方式设置:
- 配置 redis.conf 的 hz 选项,默认为10 (即 1 秒执行 10 次,值越大说明刷新频率越快,对 Redis 性能损耗也越大)
- 配置 redis.conf 的 maxmemory 最大值,当已用内存超过 maxmemory 限定时,就会触发主动清理策略
2、淘汰策略:当redis使用内存超过配置最大内存时,如果再有数据插入缓存,改如何处理,这就涉及到数据的淘汰策略,和定期删除中第二点
应该是相同的内容。其实我觉得定期删除中,不应该加入第二点内容,第二点和淘汰策略就是一回事,应该直接讲解淘汰策略就完事了。
淘汰策略有8中:
1. no eviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
2. allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键
3. volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键
4. allkeys-random:加入键的时候如果过限,从所有key随机删除
5. volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐
6. volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
7. volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
8. allkeys-lfu:从所有键中驱逐使用频率最少的键
对LRU做一个简单说明:
1. 新增key value的时候首先在链表结尾添加Node节点,如果超过LRU设置的阈值就淘汰队头的节点并删除掉HashMap中对应的节点。
2. 修改key对应的值的时候先修改对应的Node中的值,然后把Node节点移动队尾。
3. 访问key对应的值的时候把访问的Node节点移动到队尾即可。
Redis的LRU实现
Redis维护了一个24位时钟,可以简单理解为当前系统的时间戳,每隔一定时间会更新这个时钟。每个key对象内部同样维护了一个24位的时钟,
当新增key对象的时候会把系统的时钟赋值到这个内部对象时钟。比如我现在要进行LRU,那么首先拿到当前的全局时钟,
然后再找到内部时钟与全局时钟距离时间最久的(差最大)进行淘汰,这里值得注意的是全局时钟只有24位,按秒为单位来表示才能存储194天,
所以可能会出现key的时钟大于全局时钟的情况,如果这种情况出现那么就两个相加而不是相减来求最久的key。
参考: