← 返回题目列表

Redis 的内存淘汰策略有哪些?LRU 和 LFU 有什么区别?

高频 中等 第 13 / 26 题 更新于 2026/10/03
Redis淘汰策略LRULFU
学习 AI 实战项目

简化版

Redis 内存达到 maxmemory 后,会按配置的淘汰策略删除部分 key。常见策略有 noeviction、volatile-lru、allkeys-lru、volatile-ttl、volatile-random、allkeys-random、volatile-lfu、allkeys-lfu。LRU 淘汰最近最少使用的 key,看“最近有没有访问”;LFU 淘汰访问频率低的 key,看“访问次数多不多”。

详细版

Redis 淘汰策略分两类:只淘汰设置了过期时间的 key(volatile),或在所有 key 中淘汰(allkeys)。

策略含义适合场景
noeviction不主动淘汰,需要增内存的命令可能报错宁可拒绝写也不自动驱逐
allkeys-lru所有 key 中淘汰近似 LRU通用缓存
volatile-lru只在设置 TTL 的 key 中淘汰 LRU混合缓存与重要数据
allkeys-lfu所有 key 中淘汰低频 key热点稳定场景
volatile-lfuTTL key 中淘汰低频 key有过期时间的热点缓存
volatile-ttl在 TTL Key 中优先淘汰最早过期者希望优先清短 TTL
allkeys-random在所有 Key 中随机淘汰访问价值接近时
volatile-random在 TTL Key 中随机淘汰仅允许驱逐 TTL Key

如果 Redis 只是缓存,常用 allkeys-lru 或 allkeys-lfu。如果 Redis 里混有不能随便淘汰的数据,要谨慎使用 allkeys 类策略,最好从架构上隔离不同用途。

完整版教学

一、为什么需要淘汰策略

Redis 是内存数据库,内存有限。设置 maxmemory 后,当写入新数据导致内存超限,Redis 必须决定是拒绝写入,还是删掉一些旧 key 给新 key 腾空间。这个决策就是淘汰策略。

缓存系统通常允许丢弃部分 key,因为丢了还能从数据库重建;但如果 Redis 存的是会话、队列、锁、计数等关键数据,随便淘汰就可能造成业务错误。所以策略选择首先要看 Redis 在系统里的角色。

二、volatile 和 allkeys 的区别

volatile 类策略只从设置了过期时间的 key 中选择淘汰对象。没有 TTL 的 key 不会被淘汰。allkeys 类策略会从所有 key 中选择,无论有没有 TTL。

如果 Redis 专门做缓存,所有数据都可重建,allkeys 更直接。如果 Redis 里混放了缓存和不能丢的数据,volatile 看起来更安全,但更好的做法是拆实例或拆库,避免不同可靠性要求的数据混在一起。

三、LRU 和 LFU 怎么选

LRU 关注最近访问时间。一个 key 最近没被访问,就容易被淘汰。它适合访问热点变化较快的场景,比如新闻、活动页、搜索结果。

LFU 关注访问频率。一个 key 长期被访问很多次,即使短时间没访问,也不容易被淘汰。它适合热点比较稳定的场景,比如基础配置、热门商品、长期热门内容。

Redis 的 LRU/LFU 都是近似实现,不会维护全局精确排序。LRU 根据采样 Key 的空闲时间选择候选;LFU 也会采样,但 Redis 对象元数据中的频率计数不是简单累计次数,而是概率增长并随时间衰减,相关行为受 lfu-log-factor 和 lfu-decay-time 影响。衰减让曾经的热点最终有机会被淘汰。

maxmemory 64gb
maxmemory-policy allkeys-lfu
lfu-log-factor 10
lfu-decay-time 1

这些只是配置示例,不是通用推荐值;maxmemory 要根据宿主机余量确定,LFU 参数要用真实访问分布压测。

四、noeviction 的含义

noeviction 不会为新写入主动淘汰 Key;达到 maxmemory 后,需要额外分配内存的命令通常会返回错误,纯读以及部分不增加内存的操作仍可能执行。这适合宁可拒绝写也不允许自动驱逐的场景,但它不是持久性或不丢数据保证,业务还必须正确处理写失败。

作为纯缓存时,noeviction 往往不是好选择,因为内存满后新热点写不进去,缓存命中率会恶化。纯缓存更常用 allkeys-lru 或 allkeys-lfu。

五、淘汰策略之外还要做什么

淘汰策略只是最后防线。更重要的是容量规划、key 大小控制、TTL 设计、热点监控。大 key 会让内存快速膨胀,过长 TTL 会让冷数据长期占内存,缺少监控会让你直到写入报错才发现内存满了。

生产上要监控 used_memory、maxmemory、evicted_keys、命中率、Big Key、延迟和碎片率。如果 evicted_keys 持续增长且命中率下降,说明内存不足或缓存设计有问题;若淘汰时延迟升高,还要检查淘汰采样成本、大对象释放和写入突发。

六、面试追问与工程边界

面试官常会追问“内存满了只调淘汰策略够不够”。不够。淘汰策略只能在内存不足时被动删 key,真正的问题可能是 key 设计不合理、TTL 太长、大 key 太多或缓存了不该缓存的数据。要结合容量评估和数据治理一起做。

还要注意业务语义。被淘汰的 Key 应该是可重建的缓存数据。如果 Redis 里放了分布式锁、消息状态、会话等关键数据,被 allkeys 策略淘汰可能造成严重业务问题。不同可靠性的数据最好拆实例,不要指望一个淘汰策略兼顾所有场景。

七、候选集为空与容量水位

volatile 系列只从带 TTL 的 Key 中选择。如果实例已经达到 maxmemory,但没有可淘汰的带 TTL Key,新增内存的命令会像 noeviction 一样失败;它不会转而删除无 TTL Key。因此“重要数据不设 TTL、普通缓存设 TTL”只有在普通缓存始终留有足够候选和空间时才成立,混部仍可能互相挤压。

容量不能贴着 maxmemory 运行。假设实例上限 64GiB,业务数据 52GiB,看似还有 12GiB,但还需考虑复制/AOF 缓冲、客户端输出缓冲、内存碎片和 fork 写时复制。应根据压测设运行水位,并在淘汰持续发生前扩容或降低数据集;maxmemory 限制的口径与操作系统 RSS 也不是同一个数。

策略验证要用真实访问分布压测。例如突发热点适合 LRU,长期稳定热点可能由 LFU 保留得更好;若 LFU 衰减过慢,历史热点会占住内存,过快又近似短期 LRU。选择策略后观察命中率、淘汰速率和业务回源成本,而不是只看策略名称。

淘汰策略决定“压力到来时牺牲谁”,容量规划决定“是否长期处在必须牺牲数据的状态”。

八、过期删除与内存淘汰不是一回事

TTL 到期是业务生命周期结束,Redis 通过访问时的惰性删除和后台主动过期回收这些 Key;淘汰则是在 maxmemory 压力下,即使 Key 尚未到期也按策略驱逐。两者触发条件不同,监控时也要区分 expired_keys 与 evicted_keys。

现象更可能的原因排查重点
expired_keys 上升大批 TTL 到期TTL 分布、是否缺少抖动
evicted_keys 上升内存水位触发淘汰容量、数据集、策略
写命令 OOM、淘汰为 0noeviction 或无候选当前策略、TTL 候选集
RSS 远高于 used_memory碎片或进程额外内存allocator、fork、缓冲区

Key 被淘汰后,下次访问会 miss 并回源。若淘汰集中在热点 Key,数据库 QPS 与延迟会同步上升;因此评估策略不能只看释放了多少内存,还要看被驱逐数据的重建成本。一个 1KB 但每秒万次访问的 Key,业务价值可能高于一个 100KB 冷 Key。

九、怎样安全切换策略

从 LRU 切到 LFU 后,频率信息需要通过真实访问逐步形成,不能假设切换瞬间就得到稳定的热点排序。应先在相似流量实例灰度,保持相同数据集和水位,对比命中率、回源 QPS、P99 和淘汰速率,再决定扩大范围。

切换策略不会解决已经超出容量的数据集,也不会拆分 Big Key。若持续淘汰是因为版本化 Key 未清理或某个集合异常增长,应先修复 Key 生命周期;把策略来回切换只会改变被牺牲的对象。

十、常见误区与追问

  • 误区:LRU 总能淘汰最不重要数据。 Redis LRU 是近似采样,且最近使用不等于业务价值最低。
  • 误区:noeviction 最安全。 内存满后写请求会失败,业务要能处理错误。
  • 误区:volatile 策略总能腾出空间。 没有带 TTL 的候选 Key 时,需要增加内存的命令仍会失败。
  • 误区:淘汰策略可以替代 TTL 设计。 TTL 体现业务生命周期,淘汰只是在内存压力下兜底。
  • 追问:LRU 和 LFU 区别是什么? LRU 看最近访问时间,LFU 看访问频率。
  • 追问:volatile 和 allkeys 区别是什么? volatile 只淘汰设置过期时间的 key,allkeys 面向所有 key。
  • 追问:如何选择策略? 缓存型 Redis 常用 allkeys-lru/lfu,混合存储要谨慎隔离。
  • 追问:LFU 计数会不会永远增长? 不会,它采用概率计数并按配置随时间衰减,不是原始访问次数。

十一、加强记忆

Redis 淘汰策略解决内存满了删谁的问题。volatile 只淘汰有 TTL 的 key,allkeys 淘汰所有 key;LRU 看最近访问,LFU 看访问频率;noeviction 不删但写入报错。纯缓存常用 allkeys-lru/allkeys-lfu,混放重要数据要谨慎,最好隔离实例。策略之外还要控大 key、设合理 TTL、监控淘汰和命中率。