⏳ 过期与淘汰
惰性删除 · 定期删除 · 八种淘汰策略 · maxmemory 设计
1. Redis 的过期键删除策略?为什么是"惰性+定期"组合?
- 惰性删除:访问时检查 key 是否过期,过期则删除。优点:没有额外的后台扫描开销(但每次访问键仍要做一次过期检查,并非真的零开销);缺点:过期但没被访问的 key 一直占内存
- 定期删除:后台定时任务随机抽样一批带过期时间的 key,删除过期的(默认每秒 10 次,每次抽查约 20 个,过期比例高则多删几轮)。优点:主动清理;缺点:不能保证全删干净(随机抽样)
- 定时删除(不用):key 到期立即删,需定时器,CPU 开销大
为什么组合:惰性兜底(保证过期 key 最终会被清理)+ 定期主动(控制内存峰值)。两者都执行,同一 key 谁先触发谁删。
🎯 面试要点
- 主从架构:过期删除由主库触发(主删了发 DEL 给从库);从库不主动删,读从库返回已过期但未删的数据也不返回(主库 DEL 同步前)——一致性细节
- 惰性删除不释放内存的场景:大量过期 key 无人访问 → 内存居高不下 → 配合 maxmemory 淘汰兜底
2. 内存淘汰策略有哪些?怎么选?
触发条件:内存达到 maxmemory 上限后,新写入按策略淘汰旧数据(或拒绝写入)。八种:
- 不淘汰:
- noeviction:写命令直接报错(OOM command not allowed)。默认策略,当数据库用时必须显式配置
- LRU(最近最少使用)近似实现:
- allkeys-lru:所有 key 中淘汰最久未用
- volatile-lru:只淘汰设了过期时间的 key 中最久未用
- LFU(最不经常使用,Redis 4.0+):按访问频率淘汰
- allkeys-lfu / volatile-lfu
- 随机:allkeys-random / volatile-random
- ttl:volatile-ttl(淘汰剩余 TTL 最短的)
为什么是"近似 LRU":真实 LRU 要维护双向链表(内存代价大)。Redis 在对象头记录 lru 时间戳(24 bit,秒级精度,约 194 天循环;LFU 模式下这 24 bit 被拆成 16 bit 衰减时间 + 8 bit 计数器),淘汰时抽样 5 个(maxmemory-samples),淘汰最旧的。抽样代替全表扫描。
缓存场景的标准配置
maxmemory 4gb
maxmemory-policy allkeys-lru # 纯缓存:所有 key 参与 LRU 淘汰
maxmemory-samples 5 # 抽样数,越大越接近真 LRU,CPU 略增
# 业务数据(不可随意丢)→ 别开淘汰,监控告警 + 扩容
# 热点极不均匀 → lfu 优于 lru(防止"偶用一次的热 key"被误淘汰)
🎯 面试要点
- volatile-* 系列的前提:key 都设了过期时间;全都没设 → 退化为 noeviction 报错
- LFU vs LRU:LRU 看"多久没用",LFU 看"用得多不多";LFU 适合防热 key 被扫淘汰
- 监控:INFO memory 看 used_memory/maxmemory 比例,接近 100% 预警
- 淘汰与过期是两回事:过期是"key 到点失效",淘汰是"内存不够腾空间"——别混