一、过期键删除策略(针对“带 TTL 的 Key”)

Redis 采用 “惰性删除 + 定期删除” 的组合策略,在 CPU 开销和内存占用之间取得平衡。

1. 惰性删除(Lazy Expiration)

  • 触发时机访问 Key 时(如 GETSETDEL等命令执行前)。
  • 逻辑:在 db.c/expireIfNeeded()函数中,检查 Key 是否带有过期时间且已过期。如果是,则直接删除该 Key,然后视为 Key 不存在。
  • 优点:CPU 友好,不浪费资源在没人访问的过期 Key 上。
  • 缺点内存不友好。如果过期 Key 永远不被访问,它们会一直占用内存(内存泄漏)。这就是为什么需要配合“定期删除”。

2. 定期删除(Active Expiration)

  • 触发时机时间事件触发(Redis 内部定时任务 serverCron,默认每 100ms 执行一次)。
  • 逻辑(重点,面试常考):
    1. 随机抽样:从设置了过期时间的 Key 字典中,随机选出 20 个 Key(数量由 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_CRON定义)。
    2. 删除过期键:遍历这 20 个,删除其中已过期的。
    3. 循环控制:如果这 20 个里有 超过 25% 的 Key 过期(即 >= 5 个),Redis 认为过期 Key 密度很高,会立即再次随机抽取 20 个继续删除,==直到它少于这个百分比==。
    4. 时间限制:为了防止阻塞主线程,定期删除有执行时间上限(默认不超过 25ms)。如果超时,会退出等待下一轮。

==以上都是单线程去执行,一把来说阻塞的时间很短,因为:==

==1. 大Key的删除可以用UNLINK异步删除,主线下只做逻辑删除快速返回==

==2. 定期删除的执行时间也是有上限的==

二、内存淘汰策略(针对“内存满了”)

当 Redis 使用的内存达到 maxmemory限制时,再写入数据就会触发内存淘汰。

主要分为以下三种策略

  1. noeviction: 不进行淘汰:拒绝写入,报错
  2. volatile: 淘汰设置了过期时间的
  3. allkeys: 淘汰所有的数据

然后其中具体的还有很多细分,主要的记住两个:

LRU:淘汰最久未使用

LFU:淘汰最少使用

主流策略是使用allkeys-lfu