redis内存淘汰策略导致延迟的本质是主线程同步释放大key内存,只有开启lazyfree-lazy-eviction且版本≥6.0才能将释放工作移交后台线程,从而避免p99延迟尖峰和qps断崖下跌。

Redis内存淘汰策略对延迟的影响不是“有没有”,而是“卡不卡主线程”——只要没开 lazyfree-lazy-eviction,单次淘汰一个大 zset 或 hash 就可能阻塞主线程 5–50ms,直接导致 P99 延迟尖峰、客户端超时、QPS 断崖下跌。
eviction 事件为什么在 LATENCY HISTORY 里看不到
不是监控没开,而是根本没走到淘汰逻辑:
-
maxmemory-policy是noeviction:写失败直接返回(error) OOM command not allowed when used memory > 'maxmemory',压根不触发淘汰 -
used_memory_human远低于maxmemory:比如设了 6GB,但实际只用了 4GB,再怎么压测也淘汰不了 - 用的是
volatile-lru,但所有 key 都没设EXPIRE:没有候选键,evicted_keys永远为 0 -
latency-monitor-threshold设太高(如 100ms),而真实淘汰耗时在 3–8ms,全被过滤掉了
最稳的验证顺序:INFO memory 看 evicted_keys 是否上涨 → 再查 LATENCY LATEST;如果前者动了后者空,基本就是阈值设高了。
为什么开了 lazyfree-lazy-eviction 还是卡
常见配置失效场景,和版本、开关、生效方式强相关:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- Redis 版本 evictKeysRandom 和
evictLruKeys函数仍走同步释放路径 - 配置写成
lazyfree-eviction yes(漏掉-lazy-):Redis 启动时静默忽略,CONFIG GET lazyfree*查不到该值 - 改完
redis.conf没重启,或只执行CONFIG REWRITE没CONFIG RELOAD:配置未加载进运行时 - 只开了
lazyfree-lazy-user-del:这是给UNLINK用的,和自动淘汰完全无关
生效后应观察两个指标:INFO MEMORY 中的 lazyfree_pending_objects 在淘汰发生时短暂上升;redis-cli --stat 显示 evicted_keys 上涨期间 instantaneous_ops_per_sec 无断崖下跌。
allkeys-lru 和 allkeys-lfu 对延迟的实际差异
算法本身不直接导致延迟差异,真正影响响应时间的是“淘汰时释放什么”:
-
allkeys-lru:倾向淘汰冷数据,但如果冷数据是个 200MB 的hash,照样会卡主线程(未开 lazyfree 时) -
allkeys-lfu:保留高频访问键,但低频键若体积小(如大量 1KB 的字符串),淘汰开销反而更低;配合lfu-decay-time和lfu-log-factor调优后,能减少无效扫描 - 真正降低延迟的关键不是选 LRU 还是 LFU,而是避免淘汰大 Key —— 所以业务侧要控制单 key 大小(比如把百万级
zset拆成多个带分片后缀的 key)
LFU 在冷启动阶段容易误杀新热点(因计数器初始值低),需调低 lfu-log-factor 加速计数器增长;而 LRU 对突发访问更敏感,可能把刚热起来的 key 提前淘汰。这些行为差异不会抬高单次延迟,但会影响缓存命中率,间接拉高后端负载和整体链路延迟。
淘汰延迟最隐蔽的坑在于:它不报错、不打日志、不触发告警,只表现为周期性 P99 尖峰和客户端 timeout。一旦怀疑是这个原因,别猜,先确认 evicted_keys 是否增长,再看 lazyfree_pending_objects 是否有波动 —— 其他都是干扰项。










