过期与内存淘汰
两个容易混的概念:过期是把到期的 key 删掉(TTL 到了),淘汰是内存满了挑 key 腾空间。一个管生命周期,一个管容量上限。
过期删除策略
Redis 用惰性删除 + 定期删除组合:
| 策略 | 机制 | 问题 |
|---|---|---|
| 惰性删除 | 访问 key 时才检查是否过期,过期就删 | 过期但没人访问的 key 一直占内存 |
| 定期删除 | 每秒 10 次,随机采样一批 key 检查过期 | 采样不全面,仍可能有残留 |
| 惰性 + 定期 | 组合兜底 | 大量过期 key 时内存压力仍在,等淘汰兜底 |
组合效果:过期 key 不会立刻消失,但也不会无限堆积。生产上大量 key 同时过期(缓存雪崩的诱因之一)要靠 TTL 加随机值打散。
内存淘汰:8 种策略
maxmemory 设置内存上限,超限后按 maxmemory-policy 淘汰:
| 策略 | 范围 | 行为 |
|---|---|---|
| noeviction(默认) | 全部 | 不淘汰,写命令直接报错 |
| allkeys-lru | 全部 key | 淘汰最久未访问 |
| volatile-lru | 只限设了 TTL 的 | 同上,范围收窄 |
| allkeys-lfu | 全部 key | 淘汰访问频率最低 |
| volatile-lfu | 只限设了 TTL 的 | 同上 |
| allkeys-random | 全部 key | 随机淘汰 |
| volatile-random | 只限设了 TTL 的 | 随机淘汰 |
| volatile-ttl | 只限设了 TTL 的 | 淘汰剩余 TTL 最短的 |
记忆口诀:8 种 = noeviction(不淘汰)+ 3 种算法(lru/lfu/random)乘 2 个范围(allkeys/volatile)+ volatile-ttl(淘汰 TTL 最短)。volatile 系要求 key 都设 TTL,缓存场景常用 allkeys-lru 或 allkeys-lfu。
LRU 与 LFU
Redis 的 LRU 是近似 LRU:不维护精确访问时间链表,而是采样(默认 5 个 key)淘汰最旧的,兼顾性能。maxmemory-samples 调大更精确但更慢。
- LRU:淘汰最久未使用。缺陷:一次批量访问让冷 key 变“热”,之后不再访问却占着位置
- LFU(4.0+):淘汰访问频率最低。用计数器衰减模拟时间流逝,抗“一次性热点”更好
选型:读多写少的稳定业务用 LRU;有突发热点或访问模式随时间变化的用 LFU。
面试追问
- 过期和淘汰的区别? 过期是 TTL 到了删 key;淘汰是内存满时按策略腾空间。淘汰可能删掉没过期的 key
- 惰性删除的问题? 过期不访问的 key 一直占内存,所以配定期删除兜底
- 8 种淘汰策略怎么记? 算法(lru/lfu/random/ttl)乘范围(allkeys/volatile),加 noeviction
- Redis 的 LRU 是精确的吗? 不是,近似 LRU,采样 5 个淘汰最旧。精确 LRU 维护成本高
- 什么场景用 LFU? 访问频率比新鲜度更重要的场景,防一次性热点。Redis 4.0+ 支持