volatile-lru/lfu不工作根本原因是只淘汰带ttl的键,若数据全为永久键(ttl=-1)则策略失效,内存满时如noeviction般报oom错误;须检查ttl分布并改用allkeys策略。

Redis内存达到maxmemory后不自动释放空间,根本原因不是“没触发淘汰”,而是策略选错或配置缺失——比如用了noeviction(默认值),或者设置了volatile-lru但实际数据都没设过期时间,导致淘汰逻辑直接失效。
为什么 volatile-lru / volatile-lfu 突然不工作了
这类策略只作用于带EX、PX等TTL的键,一旦你存的全是永久键(如SET user:1001 "Alice"),它们就完全被跳过。此时即使内存爆满,Redis也像noeviction一样拒绝写入,报错OOM command not allowed when used memory > 'maxmemory'。
- 检查当前键的过期状态:
SCAN 0 MATCH * COUNT 1000+ 对每个key执行TTL keyname,看返回是否普遍为-1(永久)或-2(不存在) - 确认业务代码中是否漏加过期时间,尤其是缓存类写入路径
- 若确实需要保留永久键,又想启用LFU/LRU淘汰,必须切换到
allkeys-lru或allkeys-lfu
allkeys-lru 和 allkeys-lfu 的实际表现差异
allkeys-lru依赖“最近访问时间”,适合访问模式有明显时间局部性的场景(比如用户会话在登录后1小时内高频读取);allkeys-lfu依赖“访问频次计数”,更适合长尾分布+强热点的场景(如首页Banner被查1000次,而冷门商品页只被查1次)。
-
allkeys-lru在Redis中是近似实现:每次随机采样5个key,淘汰其中空闲时间最长的那个,不是全量扫描,所以有小概率误删 -
allkeys-lfu用衰减计数器防止历史访问长期影响决策,但计数器本身有精度限制(4位计数+周期衰减),超高频访问可能溢出 - 如果业务写多读少、或访问极不均匀(比如突发流量打爆某几个key),
allkeys-lfu可能比allkeys-lru更稳定
如何验证当前生效的淘汰策略是否真在运行
不能只看CONFIG GET maxmemory-policy返回值,要观察淘汰行为是否真实发生:
- 监控指标
evicted_keys:用INFO memory查,该值持续增长才说明淘汰已触发 - 对比
used_memory_peak和used_memory:若前者远高于后者,说明淘汰确实在腾空间 - 开启慢日志并过滤
evict相关事件:CONFIG SET slowlog-log-slower-than 0+SLOWLOG GET 10,看是否有evict动作记录 - 注意:
volatile-ttl策略下,evicted_keys增长快但可能误伤即将自然过期的键,不适合长期缓存
真正容易被忽略的是策略与数据生命周期的匹配度——比如用allkeys-lfu存临时Token,结果因为频次低被秒删;或者用volatile-lru存用户资料但忘了加EX,等于白配。策略本身没有优劣,只有和业务读写特征对齐才有意义。











