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

作者:技术拾光

时间:2026-05-05

浏览:133

Redis怎样处理淘汰策略引起的响应延迟_升级Redis6并开启lazyfree异步删除 开启 lazyfree-lazy-eviction yes 且 Redis ≥ 6.0 后,淘汰策略触发的内存释放由后台线程异步执行,主线程不再被同步释放大 Key 卡住。 淘汰策略引发的响应延迟,根源其实很清

文章目录

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

开启 lazyfree-lazy-eviction yes 且 Redis ≥ 6.0 后,淘汰策略触发的内存释放由后台线程异步执行,主线程不再被同步释放大 Key 卡住。

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

淘汰策略引发的响应延迟,根源其实很清晰:主线程在同步释放大Key内存时被“卡”住了。好消息是,只要你的Redis版本不低于6.0,并且正确开启了对应的lazyfree配置,就能把这部分繁重的释放工作交给后台线程,主线程几乎感知不到,服务自然也就流畅了。

为什么 maxmemory 淘汰会卡住主线程

当内存使用达到maxmemory上限,Redis开始根据maxmemory-policy(比如allkeys-lru)驱逐Key时,默认走的是同步释放的老路:找到一个待淘汰的Key → 读取它的value → 然后递归释放所有底层数据结构(想象一下一个包含百万元素的zset,其跳表节点有多少)。整个过程,主线程被全程阻塞。结果就是,QPS(每秒查询率)断崖式下跌,P99延迟(99%的请求响应时间)直线飙升,这几乎是必然现象。

这并非配置错误,而是Redis 6.0之前的设计使然。即便你用的是volatile-lfu这类策略,只要没开启lazyfree,主线程被卡住的情况照样会发生。

lazyfree-lazy-eviction 必须显式开启

Redis默认关闭了所有lazyfree场景,内存淘汰也不例外。所以,你必须在redis.conf配置文件中明确写上这一行:

lazyfree-lazy-eviction yes

这里需要特别注意:lazyfree-lazy-eviction这个开关,专门控制「因内存不足触发的Key驱逐」是否采用异步释放。它和另外两个开关——lazyfree-lazy-expire(控制过期键删除)以及lazyfree-lazy-user-del(控制DEL/UNLINK命令)——是相互独立、各管一摊的。

实践中,有几个常见的配置误区:

  • 只开启了lazyfree-lazy-user-del,以为“删除快了”就能覆盖淘汰场景——实际上对淘汰延迟无效。
  • 配置项写成了lazyfree-eviction yes(漏掉了中间的-lazy-)——Redis启动时会静默忽略这行配置。
  • 修改配置后忘记重启Redis实例,或者没有执行CONFIG REWRITE和CONFIG RELOAD——导致配置根本没有生效。

UNLINK 替代 DEL 并不能解决淘汰卡顿

很多朋友知道UNLINK是异步删除命令,于是想用它来缓解淘汰压力。但这里有个关键区别:UNLINK是客户端主动发起的删除命令的异步入口,而内存淘汰是由Redis内部机制自动触发的,走的是evictKeysRandom或evictLruKeys等内部函数路径。两者完全是两条线。

所以,别指望用UNLINK命令来解决淘汰导致的卡顿。真正起作用的组合只有一个:lazyfree-lazy-eviction yes加上Redis版本≥6.0。

如何验证配置已经生效了呢?可以试试这几个方法:

  • 观察INFO MEMORY命令输出中的lazyfree_pending_objects指标,淘汰发生后,这个值应该会短暂上升,随后逐渐归零。
  • 使用redis-cli --stat监控,在evicted_keys(被驱逐的Key数)上升期间,看看instantaneous_ops_per_sec(瞬时每秒操作数)是否保持稳定。
  • 在淘汰高峰期,抓取redis-server进程的线程栈(例如使用gstack $(pidof redis-server)),检查主线程是否长时间停留在freeObj或dictRelease这类内存释放函数的调用栈中。

异步释放不是免费的,内存回收有滞后性

开启lazyfree-lazy-eviction固然能解放主线程,但异步释放并非没有代价。最直接的影响就是内存回收的滞后性:被淘汰Key所占用的内存,不会立刻归还给操作系统,而是由后台的BIO(Background I/O)线程逐步清理。这意味着:

  • INFO MEMORY中的used_memory指标下降会变慢,可能比实际淘汰时间晚上几百毫秒甚至几秒。
  • 如果淘汰的速率持续高于BIO线程的处理能力(比如每秒要淘汰上百个50MB的大Hash),lazyfree_pending_objects队列就会持续堆积,最终仍有可能触发系统的OOM Killer。
  • BIO线程数默认只有1个。虽然可以调大io-threads参数,但请注意,这个参数主要影响AOF重写和RDB保存。lazyfree使用的是独立的BIO_LAZY_FREE任务队列,并不受io-threads控制。

最后,也是最容易被忽略的一点:lazyfree只改变了内存释放的时机,并没有改变Redis淘汰Key的决策逻辑。如果你的maxmemory-policy本身设置就不合理(例如,在需要写入的场景下错误地使用了noeviction策略),那么无论异步释放开得多彻底,也解决不了根本问题。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›