过期删除与缓存淘汰
一、过期键删除策略(针对“带 TTL 的 Key”)
Redis 采用 “惰性删除 + 定期删除” 的组合策略,在 CPU 开销和内存占用之间取得平衡。
1. 惰性删除(Lazy Expiration)
- 触发时机:访问 Key 时(如
GET、SET、DEL等命令执行前)。 - 逻辑:在
db.c/expireIfNeeded()函数中,检查 Key 是否带有过期时间且已过期。如果是,则直接删除该 Key,然后视为 Key 不存在。 - 优点:CPU 友好,不浪费资源在没人访问的过期 Key 上。
- 缺点:内存不友好。如果过期 Key 永远不被访问,它们会一直占用内存(内存泄漏)。这就是为什么需要配合“定期删除”。
2. 定期删除(Active Expiration)
- 触发时机:时间事件触发(Redis 内部定时任务
serverCron,默认每 100ms 执行一次)。 - 逻辑(重点,面试常考):
- 随机抽样:从设置了过期时间的 Key 字典中,随机选出 20 个 Key(数量由
ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_CRON定义)。 - 删除过期键:遍历这 20 个,删除其中已过期的。
- 循环控制:如果这 20 个里有 超过 25% 的 Key 过期(即 >= 5 个),Redis 认为过期 Key 密度很高,会立即再次随机抽取 20 个继续删除,==直到它少于这个百分比==。
- 时间限制:为了防止阻塞主线程,定期删除有执行时间上限(默认不超过 25ms)。如果超时,会退出等待下一轮。
- 随机抽样:从设置了过期时间的 Key 字典中,随机选出 20 个 Key(数量由
==以上都是单线程去执行,一把来说阻塞的时间很短,因为:==
==1. 大Key的删除可以用UNLINK异步删除,主线下只做逻辑删除快速返回==
==2. 定期删除的执行时间也是有上限的==
二、内存淘汰策略(针对“内存满了”)
当 Redis 使用的内存达到 maxmemory限制时,再写入数据就会触发内存淘汰。
主要分为以下三种策略
noeviction: 不进行淘汰:拒绝写入,报错volatile: 淘汰设置了过期时间的allkeys: 淘汰所有的数据
然后其中具体的还有很多细分,主要的记住两个:
LRU:淘汰最久未使用
LFU:淘汰最少使用
主流策略是使用allkeys-lfu
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 夏天的风吹向哪里!
