面试考察点
- 基础掌握度 :面试官不仅仅是想知道 Redis 有过期策略,更是想知道你是否清楚 Redis 采用的是**惰性删除 + 定期删除**的组合方案,而不是定时删除,以及为什么要这样设计。
- 原理理解深度:考察你是否了解过期字典的内部结构,定期删除的采样逻辑(随机抽取、循环检测),以及这些设计背后的性能与内存权衡。
- 知识关联能力 :能否自然过渡到 "过期策略解决不了内存问题时怎么办" → 内存淘汰策略(
maxmemory-policy),展示完整的知识体系。
核心答案
Redis 采用惰性删除 + 定期删除两种策略配合使用:
一句话结论 :Redis不使用定时删除 (到期立即删),因为那会消耗大量 CPU 资源。而是用 "惰性 + 定期" 的组合策略,在 CPU 和内存之间取一个平衡。如果过期策略清理不过来,内存还是满了,就会触发内存淘汰策略。
深度解析
一、三种过期策略的理论对比
在讲 Redis 的方案之前,先了解一下理论上过期策略有三种:
img
上图展示了三种过期策略的理论对比:
- 定时删除 :每个 Key 设置一个定时器,到期立即删除。内存最优,但 CPU 开销太大,Redis没有采用。
- 惰性删除 :只在访问时检查。CPU 最友好,但过期不访问的 Key 会一直占内存,Redis采用。
- 定期删除 :每隔一段时间抽查。是 CPU 和内存的折中方案,Redis采用。
Redis 选择惰性 + 定期的组合策略,既不会消耗过多 CPU,又能及时清理大部分过期数据。
二、过期字典:Redis 如何记录 Key 的过期时间?
img
上图展示了 Redis 存储过期时间的内部结构:
- Redis 在每个数据库(
redisDb)中维护了两个字典:dict(主字典,存储所有 Key-Value 数据)和expires(过期字典,存储设置了过期时间的 Key 及其过期时间戳)。 - 过期字典的 key 指向主字典中的同一个 Key 对象(不是副本),所以不会额外占用太多内存。
- 当检查一个 Key 是否过期时,只需在
expires字典中查找对应的时间戳,与当前时间比较即可。
三、惰性删除的工作流程
img
上图展示了惰性删除的判断流程:
- 核心思路:每次访问 Key 时,顺便检查一下是否过期。如果过期了,就删除并返回空;没过期就正常返回数据。
- 优点:对 CPU 极度友好,只有在业务需要访问时才执行删除操作,不会浪费 CPU 资源。
- 缺点 :如果有些 Key 过期了但一直没有被访问,它们就会一直占用内存,成为 "垃圾数据"。
四、定期删除的工作流程
定期删除是 Redis 主动清理过期数据的机制,它的执行逻辑比惰性删除复杂得多。
img
上图展示了定期删除的完整流程,核心逻辑:
- 随机抽取:每 100ms 从过期字典中随机抽取 20 个 Key,检查是否过期。
- 自适应循环:如果这 20 个 Key 中过期的比例超过 25%,说明当前过期 Key 很多,就再随机抽 20 个继续清理,直到过期比例降到 25% 以下,或者执行时间超过上限(默认 25ms)。
- 为什么限制 25ms:定期删除是在 Redis 主线程中执行的,如果清理时间过长会阻塞正常请求,所以必须严格限制单次执行时长。
定期删除的局限性:
- 由于是随机抽样,总会有一些过期 Key 被遗漏,不会全扫一遍。
- 如果过期 Key 数量非常多,而随机抽取的概率有限,仍然会有大量过期 Key 残留在内存中。
五、过期策略 + 内存淘汰策略 = 完整方案
"惰性 + 定期" 只能清理过期了的 Key 。如果有些 Key 没有设置过期时间,或者过期策略清理速度跟不上新 Key 的写入速度,内存还是会满。这时就需要内存淘汰策略出场了。
arduino
# redis.conf 配置最大内存和淘汰策略
maxmemory 4gb
maxmemory-policy allkeys-lru
Redis 8 种内存淘汰策略:
生产环境推荐 :allkeys-lru(通用缓存)或allkeys-lfu(热点明显的缓存)。
面试高频追问
-
追问一:为什么 Redis 不用定时删除?
定时删除需要为每个设置了过期时间的 Key 维护一个定时器,如果同时有几十万个 Key 设置了过期时间,就会有几十万个定时器同时运行,严重消耗 CPU 资源,影响 Redis 处理正常请求的性能。Redis 作为高性能缓存,把 CPU 留给业务处理更重要。
-
追问二:LRU 和 LFU 淘汰策略的区别?
-
LRU(Least Recently Used) :淘汰最久没被访问的 Key,基于 "最近访问的数据大概率还会被访问" 的假设。Redis 的 LRU 是近似算法,随机采样 N 个 Key(默认 5 个),淘汰其中最久未访问的。
-
LFU(Least Frequently Used) :淘汰访问频率最低的 Key,基于 "访问频率高的数据更有价值" 的假设。Redis 4.0 引入,更适合热点数据明显的场景(比如 20% 的数据占 80% 的访问量)。
-
追问三:如何查看 Redis 当前内存使用情况?
bash# 查看内存使用详情 INFO memory # 关键指标: # used_memory:已用内存 # maxmemory:最大内存限制 # maxmemory_policy:当前淘汰策略
常见面试变体
- 变体一:"Redis 的 Key 过期了是怎么被删除的?"
- 变体二:"Redis 过期策略和内存淘汰策略的区别?"
- 变体三:"Redis 内存满了怎么办?"
- 变体四:"Redis 的 LRU 算法了解吗?是精确的还是近似的?"
记忆口诀
过期策略:惰性删除(访问才删)+ 定期删除(随机抽查,过期超 25% 继续抽)。
为什么不单独用一种:惰性删不干净(残留垃圾),定期删不精确(随机抽样),两者互补。
内存满了 :过期策略搞不定 → 内存淘汰策略接手 →allkeys-lru最常用。
总结
Redis 过期策略采用惰性删除 + 定期删除 的组合方案。惰性删除在访问时才检查并删除过期 Key,对 CPU 友好;定期删除每 100ms 随机抽样一批 Key 清理过期的,防止大量过期数据残留。两者互补,在 CPU 和内存之间取得平衡。如果过期策略仍无法释放足够内存,就会触发内存淘汰策略 (推荐allkeys-lru或allkeys-lfu)。