第 5 章 · 过期与内存淘汰

三个交互演示:① 过期机制可视化 · ② LRU vs LFU 对比 · ③ 8 种淘汰策略沙盒

过期机制:惰性删除 vs 定期删除

20 个 Key 各带不同 TTL 倒计时。到 0 后默认仍占着内存,要么靠「访问时惰性删除」,要么靠「后台定期扫描」才会真正消失。

已过期未删除:0 已被惰性删除:0 已被定期删除:0 定期扫描轮次:0
有效 已过期未删除(占内存) 已删除 本次访问 本次扫描
关键点:惰性删除:到期 Key 不会自动消失,只有被 GET / DEL 等命令访问时,源码 expireIfNeeded 才会真正删除它。
定期删除:默认 hz=10,每 100ms 一轮,每轮抽 20 个带 TTL 的 Key(这里简化为 5 个);如果一轮里过期比例 ≥ 25%,会立刻再抽一轮,直到 25ms 用完。
③ 没有「定时删除」!网传的「Redis 用了三种删除策略」是误区。

同样的访问序列,LRU 和 LFU 谁淘汰错了?

缓存容量都是 3。下方序列从左到右一格一格执行,对比两种算法的淘汰决策:

📚 LRU(按最近访问时间)

等待开始...
命中:0 / 未命中:0

📊 LFU(按累计访问频次)

等待开始...
命中:0 / 未命中:0
对比要点:LRU:每次访问把 Key 放到队尾,淘汰队首(最久没碰的)。
LFU:每次访问让计数器 +1,淘汰频次最低的;同频次按更老的踢。
③ 默认序列里 C 被访问 4 次(高频),LFU 会一直保住 C;而 LRU 在 D B E 之后会把 C 踢走 —— 这就是 LFU 在「持续高频热点」场景的优势。

8 种 maxmemory-policy 实战沙盒

键空间里同时有「带 TTL 的 Key(黄边)」和「不带 TTL 的 Key(灰边)」。选个策略,点「写入新 Key 触发淘汰」,看哪个被踢出:

容量:10 已用:0 累计淘汰:0 累计 OOM 报错:0
看懂这一栏: volatile-* 系列只在带 TTL 的 Key(黄边)里挑;allkeys-* 系列在所有 Key 里挑。
如果选 volatile-* 但所有 TTL Key 都被踢光后再写入,会触发 OOM 写报错(因为没设 TTL 的 Key 不可淘汰)—— 这是生产事故的常见原因!