👌redis过期策略有哪些?
口语化回答
好的,面试官,过期策略主要分为主动和被动,主动又分为定时、定期,被动就是常说的惰性清理。先说结论,redis 采取的方案是定期+惰性配合的方式来进行实现。定期策略主要是通过周期性执行的函数来扫描即将过期的键,立马将其进行失效操作。这种方式比较消耗 cpu。于是产生了定期操作,没隔多少 ms 来进行执行,这种减少了 cpu 的消耗。也能比较准时的删除过期的键。算是定时的一种优化,比较难的点就是寻求平衡。最后就是拖性删除,所有的 key 即使过期了也不会立马删除,当这个键过期之后,下一次访问的时候,才会被删除,容易造成内存泄漏的问题。最后 oom 就会触发内存淘汰策略了,优点就是大大减轻了 cpu 的压力。以上两种方式配合,能达到一个平衡。
题目解析
常考题,很多人把过期策略和淘汰策略混在一起。二者既不同,当惰性删除的时候,又有联系。大家要注意多层面来回答,注意辩证 cpu 性能的问题处理。
面试得分点
定期删除,定时删除,惰性删除,主动于被动
题目详细答案
从行为上,我们可以把过期策略分为两大点。主动删除,被动删除。主动删除又分为定时删除和定期删除。
主动删除
定时删除
当设置键的过期时间时,Redis会为该键创建一个定时器,当过期时间到达时自动删除该键。redis.c 下的 activeExpireCycle 函数实现了定期删除粗略,配合 Redis的服务器的 serverCron函数,在服务器周期执行serverCron 的时候,activeExpireCycle函数就会被调用,在一定的时间内,分多次遍历 redis 中的数据库,从数据库的expires字典中检查一部分键的过期时间,此操作是随机性的,然后删除其中的过期键。
优点:删除操作会在数据到期时立即进行,确保内存及时释放。
缺点:定时器的管理会消耗系统资源,特别是在大量键设置过期时间的情况下,删除 key 会对响应时间和吞吐量产生影响。
定期删除
Redis会定期扫描数据库中的键,并删除其中已过期的键。通过随机抽取一定数量的键,并检查它们是否过期,如果过期就删除,Redis默认每隔100ms(可以通过配置文件中的hz参数进行调整)就执行一次过期扫描任务。
配置redis.conf的hz选项,默认为10,1s刷新的频率。即1秒执行10次,相当于100ms执行一次,hz值越大,说明刷新频率越快,Redis性能损耗也越大
优点:通过限制删除操作执行的时长和频率来减少删除操作对CPU的影响,同时能有效释放过期键占用的内存。
缺点:难以确定删除操作执行的时长和频率,如果执行的太频繁,会对CPU造成负担,就变成了定时删除;如果执行的太少,则过期键长时间占用的内存没有及时释放,造成内存浪费。
内存不足
当Redis的内存达到最大限制时,还会触发内存淘汰策略,策略不同决定哪些数据会被删除以腾出空间。
no eviction:禁止淘汰,达到内存限制时拒绝新的写请求。
allkeys-lru:从所有键中淘汰最近最少使用的键。
volatile-lru:从设置了过期时间的键中驱逐最近最少使用的键。
allkeys-random:从所有键中随机驱逐键。
volatile-random:从设置了过期时间的键中随机驱逐键。
volatile-ttl:从设置了过期时间的键中驱逐剩余时间最短的键。
被动删除
惰性删除
Redis不会在键过期时立即删除它,而是在下一次访问这个键时检查其是否过期,然后删除过期的键。假设这个键已经过期,但是后面一直没有被访问,则会永远存在。不会被删除,这就是惰性删除。
惰性删除策略由db.c/expireIfNeeded函数实现,所有读写数据库的Redis命令在执行之前都会调用expireIfNeeded函数对输入键进行检查。如果输入键已经过期,那么expireIfNeeded函数将输入键从数据库中删除;如果输入键未过期,那么expireIfNeeded函数不做动作。
优点:惰性删除不会增加额外的系统开销,不浪费 cpu,只在访问时进行检查。
缺点:如果某个键永远不会被访问,即使设置了过期时间,它也不会被自动删除,造成内存泄漏问题。
Redis 实际使用的是定期删除+惰性删除的方式!定期删除减少 cpu 消耗和浪费,配合惰性删除,二次检查保险。