真实面经题目 · 原创解析

Redis 如何删除和淘汰过期数据?

Redis 过期数据的处理分两层:先通过惰性删除和定期删除清理已经到期的 key;当内存仍然超过 maxmemory 时,再按淘汰策略驱逐候选数据。面试回答要区分“过期删除”和“内存淘汰”,再说明为什么 Redis 采用抽样和渐进式清理。

出现于:字节跳动 · 后端开发

60 秒回答模板

Redis 给设置了 TTL 的 key 在过期字典中记录绝对过期时间。删除过期数据主要有两种方式:惰性删除和定期删除。惰性删除是在访问 key 时检查是否过期,过期就删除,优点是不浪费 CPU,缺点是冷数据可能长期占内存。定期删除是后台周期性从过期字典中抽样检查,发现过期比例较高会继续扫描一段时间,避免一次性全量扫描导致阻塞。除此之外,当 Redis 配置了 maxmemory 且内存达到上限时,会触发内存淘汰策略,比如 allkeys-lru、volatile-lru、allkeys-lfu、volatile-ttl、noeviction 等。过期删除解决的是 TTL 到期问题,淘汰策略解决的是内存不足问题,两者不是一回事。

考点 两条清理路径
难度 真实面经高频题
回答目标 讲清机制、边界和追问

深入解析

01

过期时间如何保存

Redis 不会把过期时间塞进 value 本身,而是在数据库对象里维护一张过期字典,key 指向实际键对象,value 是毫秒级的绝对过期时间戳。这样普通 key 和带 TTL 的 key 可以共用同一套读写结构,只有需要判断过期时才查过期字典。TTL、EXPIRE、PEXPIRE 等命令本质上都是在维护这张过期信息表。

02

惰性删除的触发点

惰性删除发生在客户端访问某个 key 时,Redis 会先判断这个 key 是否设置了过期时间以及是否已经到期。如果到期,就把 key 从主字典和过期字典中删除,然后对外表现得像 key 不存在。它的优点是只处理被访问的数据,CPU 成本很低;缺点是如果大量过期 key 后续没人访问,它们会继续占用内存,不能单独依赖这种方式。

03

定期删除的抽样机制

定期删除不是全量遍历所有带 TTL 的 key,而是在事件循环中按一定频率从过期字典抽样检查。若样本中过期比例较高,说明库里可能堆积了较多过期数据,就继续扩大清理;若比例较低,就尽快让出执行时间。这个设计在内存回收和单线程响应延迟之间做平衡,避免为了清理过期键而长时间阻塞正常请求。

04

过期删除与淘汰的边界

过期删除只处理已经达到 TTL 的 key,不管 Redis 当前内存是否紧张;内存淘汰则是在 maxmemory 限制下,内存不足时按照策略选择 key 驱逐。一个 key 即使没有过期,也可能因为 allkeys-lru 或 allkeys-lfu 被淘汰;一个 key 即使已经过期,也可能在被访问或定期扫描前暂时留在内存中。面试中必须把这两条链路分开讲。

05

删除后的副作用处理

过期 key 被删除时,不只是内存结构移除这么简单,还可能影响持久化、复制和通知机制。主节点会把删除行为传播给从节点,AOF 中会记录等价的删除命令,避免从节点或重启后再次看到已过期数据。开启键空间通知时,也可能产生过期事件。理解这些副作用,能说明你知道过期删除不只是一个本地内存回收动作。

易错点

  • 把过期删除和内存淘汰混为一谈,认为 TTL 到期就是 maxmemory 淘汰。
  • 认为 Redis 会为每个 key 创建一个独立定时器,到点立即删除。
  • 忽略冷过期 key 可能暂时占用内存,误以为过期时间到达就马上释放。
  • 只背 LRU 策略,不说明惰性删除、定期删除和抽样控制的原因。

面试官追问

为什么不直接定时扫描全部过期 key?

因为 Redis 核心命令执行主要依赖单线程事件循环,全量扫描会让正常请求长时间等待。抽样加时间限制可以把清理成本摊平,牺牲一点过期键的即时释放,换取整体延迟稳定。

过期 key 到期后一定马上消失吗?

不一定。到期只表示逻辑上不可再返回给客户端,实际删除可能发生在下一次访问、定期扫描或内存淘汰前的检查中。因此过期 key 可能短时间仍占内存。

从节点会自己删除过期 key 吗?

通常由主节点决定过期删除并把删除命令传播给从节点,以保证复制一致性。从节点读到过期数据时也会有相应判断,但最终的数据变更应以主节点传播为准。

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

volatile-lru 只在设置了过期时间的 key 中按近似 LRU 淘汰,allkeys-lru 会在所有 key 中选择候选对象。前者适合只希望临时数据被淘汰的场景,后者更像通用缓存。