很多团队设置了 maxmemory-policy,就以为 Redis 会像一个精确缓存那样自动保留最有价值的数据。这个理解有风险:Redis 的 LRU/LFU 都是近似算法。
当 used_memory 超过 maxmemory,Redis 会根据策略选择候选 key。候选不是全量排序,而是采样;策略也要区分 allkeys、volatile 和 noeviction。
先把机制边界说清楚
这一篇讨论内存达到上限后的淘汰决策,不讨论过期删除。过期是 key 的生命周期,淘汰是内存压力下的牺牲选择。
整体路径
上面这张图先把主线铺开:策略决定候选池,采样决定被淘汰对象。要判断淘汰会不会生效,得同时确认 maxmemory 是否开启、策略选的是什么、以及写入压力是否真的触发了淘汰检查。
底层机制
allkeys-lru/allkeys-lfu/allkeys-random:从所有 key 中按策略淘汰,适合纯缓存实例。volatile-lru/volatile-lfu/volatile-random/volatile-ttl:只淘汰设置了 TTL 的 key,适合缓存和非缓存混用时的有限保护。noeviction:不淘汰,内存不足时让写命令报错(读命令仍可继续)。这是maxmemory-policy的默认值。- 注意一个反直觉点:
maxmemory = 0表示不限制内存、不触发淘汰,这是maxmemory的默认值。所以「设了淘汰策略但 Redis 还是不淘汰」最常见的原因就是maxmemory没设或设成 0。 - LRU 和 LFU 都通过采样近似实现(采样数由
maxmemory-samples控制,默认 5),不维护全局精确链表——每次访问移动节点的成本会破坏单线程性能,采样 5 个已足够接近真实 LRU,调大可逼近但代价上升。LFU 用 24 位时钟和对数计数器(lfu-log-factor、lfu-decay-time)跟踪访问频率。 - 淘汰只在写命令路径上检查(
freeMemoryIfNeeded),纯读命令不会触发淘汰。
「Redis 内存满了却没淘汰」排查清单:① maxmemory 是不是 0 或没设;② 策略是 noeviction;③ 是不是只有读请求没写请求;④ volatile-* 但候选 key 都没设 TTL 导致无 key 可淘汰,退化成报错;⑤ used_memory 与实际不符(lazyfree 延迟、对象共享)。淘汰策略能帮你降级,但不能替你做数据分级。
取舍与边界
淘汰策略不是兜底神器。把缓存数据和准持久数据混在同一个实例里,再指望策略自动理解业务优先级,迟早会翻车。
典型问题:用机制化例子排查
- 纯缓存实例优先
allkeys-lfu或allkeys-lru,业务状态数据尽量独立实例。 - 使用
volatile-*时确保应被淘汰的 key 都设置了 TTL。 - 监控 evicted_keys、hit rate 和内存曲线,淘汰增加说明容量或热点模型已变化。
- 不要用淘汰策略掩盖大 key、热 key 和缓存雪崩问题。
收束:一句判断
淘汰策略能帮你降级,但不能替你做数据分级。
关于十三Tech
我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。
我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。
如果你想继续跟完这套「图解 Redis」,欢迎关注公众号 「十三Tech」。后续会继续按数据结构、底层机制、持久化、高可用和实战排查这条线更新。

