在面试中,Redis 的过期策略是考察 内存管理 和 系统稳定性 的核心考点。作为资深开发,你不能只背出“定期删除+惰性删除”,要从性能损耗、一致性以及**内存淘汰机制(Eviction)**的协同工作来讲解。
1. Redis 的双重过期检查机制
Redis 并不是在 Key 过期的那一刻就立即将其从内存中抹除(因为实时监控成千上万个 Key 会极其消耗 CPU),而是采用两种策略配合:
A. 惰性删除 (Lazy Expiration)
-
原理: 当客户端尝试访问某个 Key 时,Redis 先检查该 Key 是否过期。
-
逻辑: 如果过期,删除并返回
nil;如果没过期,返回数据。 -
优点: 对 CPU 极度友好,只有在用到时才处理。
-
缺点: 极其浪费内存。如果大量过期的 Key 永远不被访问,它们会一直霸占内存。
B. 定期删除 (Periodic Expiration)
-
原理: Redis 默认每隔 100ms 运行一次后台任务,随机抽取一批设置了过期时间的 Key。
-
逻辑:
-
从过期字典中随机抽取 20 个 Key。
-
删除其中已过期的 Key。
-
如果过期的 Key 占比超过 25%,则重复执行步骤 1(为了快速释放内存,但有时间上限,防止阻塞主线程)。
-
-
优点: 能够主动清理过期数据,防止内存堆积。
2. 容易混淆的概念:过期策略 vs 内存淘汰策略
这是面试最容易掉坑的地方。
-
过期策略: 处理的是“到了时间该消失”的数据。
-
内存淘汰策略 (Maxmemory Policy): 处理的是“内存满了,没到时间也得踢走”的数据。
当内存触达 maxmemory 限制时,Redis 会根据配置触发淘汰,常见的有:
-
allkeys-lru / volatile-lru: 淘汰最近最少使用的 Key。
-
allkeys-lfu / volatile-lfu: 淘汰最不经常使用的 Key(看频率)。
-
volatile-ttl: 优先淘汰快要过期的 Key。
-
noeviction: 直接报错,不删数据(默认策略,生产环境极危险)。
3. 资深开发必须要提的“坑” (面试加分)
A. 主从架构下的一致性问题
-
现象: 从节点(Replica)不会主动触发定期删除。
-
原理: 为了保证主从数据一致,过期删除动作由主节点(Master)发起,主节点在删除后会显式地向从节点发送一条
DEL命令。 -
面试点: 如果主从同步存在高延迟,用户可能会在从节点上读到本该过期的“脏数据”。(Redis 3.2 以后通过在从节点读取时增加逻辑判断解决了显示问题,但物理删除仍依赖主节点)。
B. 对过期时间分布的优化
-
场景: 缓存雪崩。
-
优化: 既然你知道 Redis 批量扫描过期的逻辑,如果你的业务在同一秒设置了 100 万个 Key 过期,不仅会造成 Redis 瞬间卡顿,还会导致数据库压力骤增。
-
对策: 设置过期时间时增加一个随机扰动值(Jitter),让过期时间点变得平滑。
4. 话术总结(面试直接用)
“Redis 采用了 ‘惰性删除 + 定期采样删除’ 的结合方案。惰性删除保证了 CPU 效率,定期采样则通过每秒 10 次的随机抽检来维持内存水位。
但需要注意的是,过期策略并不等同于内存淘汰策略。当内存达到阈值时,会根据
maxmemory-policy(如 LRU 或 LFU)来腾空间。在我之前的项目中,为了防止缓存雪崩,我会给过期时间加上随机数;同时,考虑到主从架构下从节点不主动删除过期的特性,我会确保业务对微小的时间差有足够的容忍度。”
追问准备:
如果面试官问你:“为什么 Redis 定期删除要随机抽样,而不是全量扫描?”
你应该从 Redis 单线程模型 和 CPU 阻塞 的角度去切入。
你现在对 LRU 和 LFU 这两种算法的区别(最近使用时间 vs 使用频率)了解得如何?这通常是紧接着过期策略之后的必考题。