Redis在运行期间一旦使用的内存达到maxmemory设定的阈值,就会按照配置的淘汰策略挑出部分键进行删除,为新写入的数据腾出空间。如果恰好被淘汰的是一个包含数百万个元素的哈希表或者一个超大的有序集合,同步删除会消耗大量CPU时间,这段时间内主线程无法处理任何其他命令,表现为延迟陡增甚至超时。lazyfree-lazy-eviction正是为了解决这类大键淘汰阻塞问题而引入的延迟释放开关。

lazyfree-lazy-eviction的基础原理与配置方式
在Redis 4.0之后,官方引入了惰性删除(lazy free)系列特性,其中lazyfree-lazy-eviction专门控制内存淘汰时的键释放行为。当该参数设为yes时,Redis在执行业务命令触发内存淘汰后,不会在主线程里直接调用同步释放函数,而是把待删除的键封装成任务,投递给后台的BIO_LAZY_FREE线程去真正回收底层数据结构与内存。
配置方法非常简单,可以在redis.conf中写入lazyfree-lazy-eviction yes,也可以通过命令行在运行时动态修改:config set lazyfree-lazy-eviction yes。需要注意的是,它只作用于因为内存不足而被淘汰的键,并不改变键的挑选逻辑。也就是说,无论是volatile-lru、allkeys-random还是volatile-ttl,选哪些键淘汰由策略决定,而选出来之后怎么删则由该参数决定。
从源码角度看,Redis在freeMemoryIfNeeded函数中判断若开启此选项,会调用dbAsyncDelete而不是dbSyncDelete。前者仅仅把键从字典中摘除,实际释放交给懒删除线程,因此主线程的淘汰路径非常轻量。这种解耦让单次命令的尾延迟显著降低,尤其适合缓存场景中存在大键的实例。
同步淘汰与延迟淘汰的性能差异对比
为了直观理解差异,我们假设一个哈希键big:user拥有五百万个字段,占用内存约八百兆。在同步淘汰模式下,主线程执行释放要遍历整个哈希表、逐个释放键值对节点,耗时可能达到几十毫秒甚至上百毫秒,期间所有连接命令排队。在延迟淘汰模式下,主线程瞬间完成键的字典摘除并返回,后台线程在几十毫秒后慢慢释放,用户侧几乎无感知。
我们可以用一段伪代码模拟两种路径的差异:
// 同步淘汰(lazyfree-lazy-eviction no)
public void evictSync(RedisDb db, String key) {
// 主线程直接释放,阻塞
HashMap<String, String> map = db.getHash(key);
for (Entry<String, String> e : map.entrySet()) {
freeEntry(e); // 耗时操作在主线程
}
db.remove(key);
}
// 延迟淘汰(lazyfree-lazy-eviction yes)
public void evictAsync(RedisDb db, String key) {
db.remove(key); // 仅摘除
BioLazyFree.submit(() -> {
HashMap<String, String> map = db.getHashBackup(key);
for (Entry<String, String> e : map.entrySet()) {
freeEntry(e); // 后台线程释放
}
});
}
从监控指标上,开启延迟淘汰后,INFO stats中的lazyfree_pending_objects会显示等待后台释放的对象数,而evicted_keys仍然正常递增。若发现该待释放数值长期很高,说明淘汰速度超过后台释放能力,可能需要降低写入压力或扩容。
不过延迟淘汰并非银弹。因为内存不会立刻归还操作系统,Redis的used_memory在键被逻辑删除后可能仍显示高位,直到后台线程完成。若依赖内存水位做告警,应区分逻辑删除与物理释放,避免误判。
生产环境调优与常见误区
很多人在开启lazyfree-lazy-eviction的同时,以为所有删除都变异步了,这是错误认知。它仅覆盖内存淘汰这一特定路径,像主动执行的DEL命令默认仍是同步,除非额外开启lazyfree-lazy-user-del。另外lazyfree-lazy-expire管的是过期键删除,与淘汰互不替代,高并发实例建议三者按业务分别评估。
在容器化部署中,若设置了内存上限为容器limit的百分之八十,开启延迟淘汰可防止OOM Killer因瞬时淘汰卡顿导致健康检查失败。但应配合maxmemory-policy合理选择,比如用allkeys-lru时大键容易被选中,此时延迟淘汰收益最大;若用volatile-ttl且大键无过期时间,则不会被淘汰,参数无意义。
最后给出一个实用的配置检查脚本思路:定期拉取config get lazyfree-lazy-eviction与info memory,当mem_fragmentation_ratio异常且lazyfree_pending_objects持续增长时,记录日志并提醒调优。这样可以在保障低延迟的同时,掌握真实内存回收节奏,让Redis在重淘汰负载下依然平稳。
Redislazyfree-lazy-evictionlazy_free修改时间:2026-08-16 09:48:28