跳转到主内容
极星编程网:以代码为星,赴技术山海!

Redis怎样处理淘汰策略引起的响应延迟_升级Redis6并开启lazyfree异步删除

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

相关文章