真实面经题目 · 原创解析

Redis的过期机制和删除机制是什么?

Redis 过期机制用于处理设置了生存时间的 key,核心数据结构是 expires 过期字典;删除过期 key 主要依赖惰性删除和定期主动过期。过期机制解决的是 key 到期后如何消失,内存淘汰解决的是内存不够时牺牲哪些 key,二者不能混淆。

出现于:阿里巴巴 · 后端开发

60 秒回答模板

Redis 会把设置了 TTL 的 key 记录到独立的过期字典中,字典的 key 指向真实键对象,value 是绝对过期时间戳。判断是否过期时,Redis 根据当前时间和过期字典中的时间戳比较。删除过期 key 主要有两种方式:惰性删除是在访问某个 key 时检查是否过期,过期就删除并返回不存在;定期主动过期是 Redis 后台周期性抽样检查带过期时间的 key,发现过期就删除,并用时间预算控制本轮清理,避免长时间阻塞主线程。TTL 返回秒级剩余时间,PTTL 返回毫秒级;过期时间的判断可以很精细,但实际物理删除不一定发生在到期瞬间。还要区分过期删除和 maxmemory 淘汰:前者基于时间,后者基于内存压力,涉及 volatile-lru、allkeys-lru、lfu、random、noeviction 等策略。大 key 删除还要关注 DEL 同步释放造成阻塞,可以用 UNLINK 或 lazyfree 异步释放。

考点 过期字典
主线 惰性删除
易错点 把过期机制说成只有定时删除,忽略 Redis 主要依赖…

深入解析

01

过期字典

Redis 并不是把过期时间直接塞进 value 对象里,而是在数据库结构中维护 expires 过期字典。普通 key-value 数据放在主字典中,过期时间放在 expires 字典中。expires 的键通常指向主字典里的同一个 key 对象,值是绝对过期时间戳。没有设置过期时间的 key 不需要额外承担 TTL 字段成本。

02

惰性删除

惰性删除发生在 key 被访问时。Redis 执行读写命令前,会检查该 key 是否设置了过期时间,以及当前时间是否已经超过过期时间。如果已经过期,Redis 会先删除该 key,再按照 key 不存在的语义返回。它简单、精确、不会扫描无关 key,但长期不被访问的过期 key 可能继续占用内存。

03

主动过期

为了解决过期 key 长期没人访问的问题,Redis 会周期性执行主动过期任务。它不会一次性遍历所有 key,因为全量扫描会阻塞主线程。典型做法是在带过期时间的 key 中抽样检查,删除已过期 key,并在一定时间预算内循环执行,在内存回收效率和请求延迟之间做平衡。

04

TTL 精度

TTL 返回 key 的剩余生存时间,单位是秒;PTTL 返回毫秒级剩余生存时间。EXPIRE、EXPIREAT 是秒级命令,PEXPIRE、PEXPIREAT 以及 SET 的 PX 参数支持毫秒级过期。Redis 存储的是绝对过期时间,判断可以按毫秒比较,但物理删除可能晚于到期时刻。

05

过期与淘汰

过期删除处理的是设置了 TTL 且已经到期的 key,关注时间语义。内存淘汰处理的是 Redis 达到 maxmemory 限制后,为了继续写入或维持内存上限而选择删除哪些 key,关注容量压力。即使一个 key 没过期,也可能因为淘汰策略被删除;即使没有达到 maxmemory,过期 key 也可能被删除。

06

淘汰策略

Redis 淘汰策略通常按候选集合分为 volatile 和 allkeys 两类。volatile-lru、volatile-lfu、volatile-random、volatile-ttl 只从设置了过期时间的 key 中淘汰;allkeys-lru、allkeys-lfu、allkeys-random 从所有 key 中淘汰;noeviction 表示内存不足时不主动淘汰,写命令可能报错。

07

大 key 删除

删除大 key 不只是从字典里摘掉引用,还可能释放大量元素和内存。如果用 DEL 删除包含大量元素的 list、set、hash、zset,释放过程可能阻塞主线程。UNLINK 会先把 key 从键空间移除,再把内存释放交给后台线程;lazyfree 相关配置也可以降低删除大 key 对请求延迟的影响。

08

复制与 AOF

在复制场景中,过期 key 的删除通常由主节点判定并传播删除命令给从节点,避免每个节点基于本地时间独立删除造成不一致。AOF 追加日志时,主节点删除过期 key 会记录对应删除命令;AOF 重写时,已经过期的 key 不会写入新的 AOF 文件。

易错点

  • 把过期机制说成只有定时删除,忽略 Redis 主要依赖惰性删除和定期主动过期。
  • 认为 key 到期瞬间一定被物理删除,没有区分过期判断精度和实际删除时机。
  • 把过期删除和内存淘汰混为一谈,没有说明 maxmemory 和淘汰策略的触发条件。
  • 只会说 LRU,不知道 volatile-lru 与 allkeys-lru 的候选集合不同。
  • 忽略大 key 删除的阻塞风险,没提 DEL、UNLINK 和 lazyfree 的差异。
  • 不知道 TTL 返回 -1、-2 的含义,排查缓存 TTL 问题时容易判断错误。

面试官追问

Redis 为什么不用定时器精确删除每个过期 key?

因为可能存在海量带过期时间的 key,为每个 key 维护独立定时器会带来很高的调度、内存和维护成本,集中到期时还会造成删除风暴。

过期 key 还没物理删除,客户端还能读到吗?

通常读不到。客户端访问 key 时会触发惰性检查,如果发现已经超过过期时间,Redis 会先删除它,再返回不存在。它可能只是物理上暂时还占着内存。

TTL 返回 -1 和 -2 分别是什么意思?

TTL 或 PTTL 返回 -2 表示 key 不存在;返回 -1 表示 key 存在但没有设置过期时间。正常正数表示剩余生存时间,TTL 单位是秒,PTTL 单位是毫秒。

volatile-lru 和 allkeys-lru 有什么区别?

volatile-lru 只会从设置了过期时间的 key 中按近似 LRU 选择淘汰对象;allkeys-lru 会从所有 key 中按近似 LRU 选择淘汰对象。

DEL 和 UNLINK 的区别是什么?

DEL 会同步删除 key 并释放相关内存,删除大 key 时可能阻塞主线程。UNLINK 会先把 key 从键空间中移除,再把内存释放交给后台线程异步执行。