← 每日面试题 学习看板

Redis 的过期策略是怎么样的?

面试题/03数据库中间件/02Redis/04内存管理与淘汰策略/Redis 的过期策略是怎么样的?.md

https://chat.deepseek.com/share/3jbnsjqfj4k4ri7jo9


面试记录 2026-09-20

题目:Redis 的过期策略是怎么样的?

难度:medium

标签:db/redis/memory, general/knowledge

评分:⭐⭐☆☆☆(2/5)

我的回答

Redis 过期策略就是给数据打上数据打上一个标识,这个东西可能会过期。然后设置好它的过期时间,这时候如果这个东西它过期了。哦,对了,少说一个,Redis 的过期策略基本上是惰性的,而不是主动触发的。它没有一个独立的线程一直在跑,这个东西过期了吗?那个东西过期了吗?它实际上是一个触发式的,就是这个 key 你二次用的时候又访问了,然后发现这个东西过期了,然后它才去考虑删的。然后另外的就是它并不是时时刻刻去扫定这个过期的数据的,这个东西是否过期了。它只是在触发的时候扫,另外是在一个有一个独立的线程去大范围的周期性的去扫。就是比如说像它的过期策略,你可以淘汰策略,还是内存处理策略。当那个内存满溢的时候如何处理?如果你设置的只是过期 Key 去进行淘汰的话,也会触发这个缓存的删除,删除这个 Redis 的过期 Key。如果你你设置了一个随机删除,它可能过不过期,随机删除的全量 Key,它可过不过期它都给你删。

点评

优点:

不足:

补充:

  1. 过期策略 = 惰性删除 + 定期删除(两个组合)
  2. 惰性删除:key 被访问时检查 TTL,过期就删
  3. 定期删除:serverCron 每 100ms 触发 activeExpireCycle,采样 20 个过期 key,过期比例 >25% 继续扫,单次最多 25ms
  4. 主线程定时器,不是独立线程——单线程模型的核心权衡
  5. 对比:主动删除(耗时)/ 惰性删除(内存浪费)/ Redis 方案(折中)
  6. 内存淘汰策略是另一个话题:8 种 maxmemory-policy(noeviction / allkeys-lru / volatile-lru / allkeys-lfu / allkeys-random / volatile-ttl 等)

完整讲解

第一部分:知识重点剖析

核心考点定位:考察对 Redis 过期键删除机制的深入理解,尤其要区分"过期策略"(Expiration Policy)和"内存淘汰策略"(Eviction Policy)。

知识点拆解:

  1. 术语先分清:过期策略(如何处理到达 TTL 的 key,两种机制组合)vs 内存淘汰策略(内存达 maxmemory 时如何腾空间,8 种策略)
  2. 过期策略两大机制:
  1. 关键澄清:不是独立线程,是主事件循环里的定时任务;采样 + 时间上限保证不阻塞
  2. 设计权衡:全扫会阻塞命令,纯惰性冷门 key 堆积;Redis 方案是 CPU 与内存的折中
  3. 实现细节:expires 字典与 db 主字典分离;EXPIRE/PEXPIRE/SET EX 写 expires;命令执行前后都可能触发 activeExpireCycle
  4. 对比其他方案:主动删除(高 CPU 低内存)、惰性删除(零 CPU 高内存)、Redis 组合(中 CPU 中内存)
  5. 工程实践:监控 expired_keys/evicted_keys;TTL 加随机抖动防雪崩;冷门 key 缩短 TTL
  6. 常见误区:过期 key 不一定立即删除;Redis 没有专门的过期线程;设置 EXPIRE 不一定按时删

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. activeExpireCycle 的具体逻辑?
  1. 如何判断过期 key 堆积?
  1. 过期 key 会立即删除吗?
  1. 过期策略和内存淘汰策略的关系?
  1. 大量 key 同时到期会怎样?
  1. Redis 7.0 对过期清理有什么优化?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,Redis 的过期策略其实是两个机制的组合:惰性删除 + 定期删除,别和内存淘汰策略混淆,那是另一个话题。

惰性删除是在 key 被访问时(lookupKey 阶段)判断 expire < now,过期就立即删。好处是零开销,坏处是冷门 key 永远不会被访问,内存一直占着。

定期删除是主线程的 serverCron 定时任务,每秒约 10 次触发 activeExpireCycle,每次从过期字典随机抽 20 个 key,统计这批里实际过期的比例:过期比例 ≤ 25% 就结束本轮(说明整体过期不多),> 25% 就继续扫,直到 CPU 时间超过 25ms 为止。这样既不阻塞主线程,又能控制过期 key 的堆积。

这里有个常见误区:很多人以为 Redis 有专门的过期线程,其实没有——单线程模型下,过期扫描是主事件循环里的定时任务,通过采样和时间限制来保证不阻塞命令。

为什么不用主动全扫?因为 Redis 单线程,全扫会阻塞所有命令。为什么不纯惰性?因为冷门 key 会堆积内存。所以是 CPU 与内存的折中。

实现细节上,过期信息存在独立的 expires 字典里,和 db 主字典分离。业务上我做过两个坑:一是把大量 key 的 TTL 设成一样(都是 24h),到点集体过期,触发缓存雪崩,后来改成 TTL + random(0, 3600) 随机抖动;二是发现 expired_keys 一直不涨但内存还在增,查下来是大量冷门 key 从没被访问,惰性删除没触发,缩短 TTL 就好了。

监控看 INFO keyspace 的 expired_keys 和 evicted_keys,前者是过期删除,后者是内存淘汰,两个数字要分开看。