04.内存管理
文章目录
问题: Redis 的过期删除策略(定期删除 + 惰性删除)是如何协同工作的?当内存达到 maxmemory 上限时,有哪些淘汰策略可选?默认策略是什么?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
过期删除策略的协同工作流程
① 惰性删除(Lazy Deletion)
- 触发时机:客户端读取或写入某个 key 时
- 操作:检查 key 是否设置了过期时间且已过期,若是则立即删除该 key,返回 nil 或执行后续逻辑
- 优点:CPU 开销极小,只在访问时检查
- 缺点:若过期 key 一直未被访问,会长期占用内存(内存泄漏风险)
② 定期删除(Active Expiration)
- 触发时机:Redis 内部定时任务(默认每秒执行 10 次,即每 100ms)
- 操作:从设置了过期时间的 key 集合中随机抽取一批(默认 20 个),删除其中已过期的 key;若本次删除比例超过 25%,则立即再次抽样循环,直到比例低于阈值
- 优点:主动清理过期 key,避免内存无限增长
- 缺点:随机抽样导致部分过期 key 可能未被及时清理(仍依赖惰性删除兜底)
两者关系:定期删除是主动清理的主力,惰性删除是最后防线。过期 key 通过定期删除大概率被回收,若遗漏则依赖惰性删除在访问时回收,最终也依赖内存淘汰策略作为极端情况下的兜底。
内存淘汰策略(maxmemory-policy)全览
| 策略 | 淘汰范围 | 淘汰规则 | 适用场景 |
|---|---|---|---|
| noeviction(默认) | 不淘汰 | 内存满时写入操作返回错误 | 不允许数据丢失的严格场景 |
| allkeys-lru | 所有 key | 淘汰最近最少使用的 key | 缓存场景,访问频率差异大(推荐) |
| volatile-lru | 仅设置了过期时间的 key | 淘汰其中最近最少使用的 key | 部分数据需持久保存,部分可淘汰 |
| allkeys-random | 所有 key | 随机淘汰 | 数据访问均匀无热点 |
| volatile-random | 仅设置了过期时间的 key | 随机淘汰 | 同上,但仅针对可过期数据 |
| volatile-ttl | 仅设置了过期时间的 key | 淘汰剩余生存时间最短的 key | 希望优先淘汰即将过期的数据 |
| allkeys-lfu(4.0+) | 所有 key | 淘汰访问频率最低的 key | 需区分冷热数据,LFU 比 LRU 更精确 |
| volatile-lfu(4.0+) | 仅设置了过期时间的 key | 淘汰其中访问频率最低的 key | 同上,但仅针对可过期数据 |
默认策略:noeviction。生产环境中如果 Redis 作为缓存,通常改为 allkeys-lru 或 allkeys-lfu。
淘汰策略的选择建议
- 缓存场景(数据可丢失):优先
allkeys-lru或allkeys-lfu,淘汰冷数据腾出空间 - 部分数据重要(如用户会话、配置):用
volatile-lru,只为可过期数据设置过期时间,重要数据不设置过期时间 - 访问均匀:
allkeys-random,避免 LRU 维护开销 - 数据有明确生命周期:
volatile-ttl,让即将过期的数据优先被淘汰
LRU 与 LFU 的实现差异(面试加分)
- 近似 LRU:Redis 不是全局维护所有 key 的精确 LRU 链表,而是随机抽样(默认 5 个 key)淘汰其中最近最少使用的,在性能和精确性之间取得平衡。可通过
maxmemory-samples配置抽样数量(越大越精确,但 CPU 开销更高)。 - LFU(Least Frequently Used,4.0 引入):淘汰访问频率最低的 key,而非最近使用时间。通过计数器记录访问次数,随时间衰减,能更好识别长期冷数据。
定时删除 vs 惰性删除 vs 定期删除对比
| 策略 | 执行时机 | 对 CPU 影响 | 对内存影响 | Redis 是否使用 |
|---|---|---|---|---|
| 定时删除 | 每个 key 到期时立即删除 | 高(大量定时器) | 最及时 | ❌ 不使用 |
| 惰性删除 | 访问 key 时 | 低 | 不及时(可能累积) | ✅ 使用 |
| 定期删除 | 周期性抽样检查 | 中 | 较及时 | ✅ 使用 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LGQ的博客!