开启 lazyfree-lazy-eviction yes 且 Redis ≥ 6.0 后,淘汰策略触发的内存释放由后台线程异步执行,主线程不再被同步释放大 Key 卡住。
淘汰策略触发的响应延迟,本质是主线程在同步释放大 Key 内存时被卡住。只要 Redis 版本 ≥ 6.0 且正确开启对应 lazyfree 配置,就能把这部分释放工作移交后台线程,主线程几乎不感知。
为什么 maxmemory 淘汰会卡住主线程
当
达到上限、Redis 根据
(如
)开始驱逐 Key 时,它默认走的是同步释放路径:找到一个待淘汰的 Key → 读取其 value → 递归释放所有底层结构(比如一个百万元素的
的跳表节点)→ 才返回。这个过程全程阻塞主线程,QPS 断崖下跌、P99 延迟飙升是常态。
这不是配置错的问题,而是 Redis 6.0 之前的设计限制。哪怕你用的是
,只要没开 lazyfree,照样卡。
lazyfree-lazy-eviction 必须显式开启
Redis 默认关闭所有 lazyfree 场景,包括淘汰驱逐。必须在
中设置:
注意:
控制的是「内存不足触发的驱逐删除」是否异步释放内存,和
(过期键)、
(DEL/UNLINK)互不影响,各自独立开关。
常见误操作:
Redis 8.2.3
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
下载
只开了
,以为“删得快”就覆盖了淘汰场景 —— 实际无效
配置写成
(漏掉
)—— Redis 启动时静默忽略该行
改完配置没重启实例,或没
+
—— 配置未生效
UNLINK 替代 DEL 并不能解决淘汰卡顿
是用户主动删除的 lazyfree 入口,它对淘汰场景完全无影响。淘汰由 Redis 内部自动触发,走的是
或
等函数路径,和客户端发什么命令无关。
所以别指望用
缓解淘汰压力。真正起作用的只有:
+ Redis ≥ 6.0。
验证是否生效的方法:
观察 INFO MEMORY 输出中的
,淘汰发生后该值应短暂上升再归零
用
监控
上升期间的
是否稳定
在淘汰高峰期抓取
进程栈:
,主线程不应长时间停留在
或
调用栈中
异步释放不是免费的,内存回收有滞后性
开启
后,被淘汰 Key 的内存不会立刻归还给操作系统,而是由 BIO 线程逐步释放。这意味着:
INFO MEMORY 中的
下降变慢,可能比实际淘汰时间晚几百毫秒到几秒
如果淘汰速率持续高于 BIO 线程处理能力(比如每秒淘汰 100 个 50MB 的 Hash),
会持续堆积,最终可能触发 OOM killer
BIO 线程数默认为 1,高负载下可考虑调大
(但仅对 AOF rewrite 和 RDB save 有效;lazyfree 使用的是独立的 BIO_LAZY_FREE 队列,不受
控制)
最易被忽略的一点:lazyfree 不改变淘汰决策逻辑,只改变释放时机。如果你的
本身就不合理(比如用了
却硬塞数据),再怎么开异步也救不了。
maxmemorymaxmemory-policyallkeys-lruzsetvolatile-lfuredis.conflazyfree-lazy-eviction yeslazyfree-lazy-evictionlazyfree-lazy-expirelazyfree-lazy-user-dellazyfree-lazy-user-dellazyfree-eviction yes-lazy-CONFIG REWRITECONFIG RELOADUNLINKevictKeysRandomevictLruKeysUNLINKlazyfree-lazy-eviction yeslazyfree_pending_objectsredis-cli --statevicted_keysinstantaneous_ops_per_secredis-servergstack $(pidof redis-server)freeObjdictReleaselazyfree-lazy-evictionused_memorylazyfree_pending_objectsio-threadsio-threadsmaxmemory-policynoeviction