在 Redis 6 中,当内存达到 maxmemory 上限时,Redis 并不会阻塞主线程去同步删除大量 Key,而是采用了懒惰驱逐(Lazy Eviction) 和**定时驱逐(Timed/Active Eviction)**相结合的混合策略。
这种设计的核心目的是:在保证内存不超限的前提下,最大程度避免主线程阻塞,保障读写请求的低延迟。
定时驱逐
这是 Redis 的主动防御机制,在后台持续、小批量地清理过期或待淘汰的 Key。
- 触发时机 :
- 每次处理客户端命令之前(
beforeSleep)。 - 每秒执行一次的定时任务(
serverCron,默认 10Hz)。
- 每次处理客户端命令之前(
- 工作方式 :
- 过期键清理:随机抽取一批设置了 TTL 的 Key 进行检查,删除已过期的。如果过期比例高,会循环多次(但单次有上限,防止阻塞)。
- 内存淘汰 :当内存超限时,根据配置的淘汰策略(如
allkeys-lru),采样少量 Key 进行淘汰。
- 特点 :
- 渐进式:每次只删除一小部分,分摊到每个时间片,对主线程影响极小。
- 预防性:在请求到来前就尽量维持内存健康水位。
注意 :Redis 6 引入了多线程 I/O ,但定时驱逐和内存淘汰逻辑仍然只在主线程执行。多线程仅用于网络读写和协议解析,不涉及数据结构的修改。
懒惰驱逐
这是 Redis 的被动兜底机制,仅在写入操作因内存不足被拒绝时才触发。
- 触发时机 :
- 客户端执行写入命令(如
SET,HSET,LPUSH)时。 - 定时驱逐未能及时释放足够内存,导致当前写入无法分配空间。
- 客户端执行写入命令(如
- 工作方式 :
- 主线程同步执行一次完整的淘汰流程,直到腾出足够空间容纳新数据。
- 如果配置了
lazyfree-lazy-eviction yes(Redis 4.0+),则大 Key 的实际内存释放会交给后台线程异步执行,主线程仅解除引用,进一步减少阻塞。
- 特点 :
- 应急性:是最后一道防线,确保写入不会因内存满而永久失败。
- 可能阻塞:若未开启 lazyfree 或 Key 较小,仍会在主线程同步删除,造成短暂延迟尖刺。
两者对比与协作关系
| 维度 | 定时驱逐 | 懒惰驱逐 |
|---|---|---|
| 触发方式 | 主动、周期性 | 被动、按需 |
| 执行频率 | 高频、小批量 | 低频、大批量(兜底) |
| 对延迟影响 | 极低(均摊) | 可能产生毛刺(除非开启 lazyfree) |
| 主要目标 | 维持内存水位平稳 | 保证写入可用性 |
| 是否可关闭 | 不可关闭(核心机制) | 可通过 maxmemory-policy noeviction 禁止淘汰(但会拒绝写入) |
协作流程:

Redis 6 相关关键配置建议
bash
# 淘汰策略(根据业务选择)
maxmemory-policy volatile-lru # 仅淘汰带TTL的Key(混合存储场景)
# maxmemory-policy allkeys-lru # 所有Key按LRU淘汰(缓存场景推荐)
懒惰释放开关(强烈建议开启)
lazyfree-lazy-eviction yes # 淘汰时异步释放内存
lazyfree-lazy-expire yes # 过期键异步释放
lazyfree-lazy-server-del yes # DEL/FLUSHALL 等命令异步释放
定时驱逐调优(一般保持默认即可)
hz 10 # serverCron 执行频率,10=每秒10次
active-defrag-enabled yes # (可选)开启主动碎片整理,减少内存浪费
生产环境注意事项
- 监控指标 :关注
evicted_keys(淘汰总数)和expired_keys(过期总数)。若evicted_keys持续增长,说明内存长期不足,需扩容或优化数据模型。 - 避免大 Key :即使开启了
lazyfree,超大 Key(如百 MB 的 Hash/Set)的解引用本身也会占用主线程 CPU。应通过MEMORY USAGE定期扫描并拆分大 Key。 - 不要依赖懒惰驱逐 :它只是兜底。如果频繁触发,说明定时驱逐跟不上写入速度,会导致 P99 延迟飙升。应调整
maxmemory预留缓冲空间,或降低写入速率。 - Redis 6 vs 7:Redis 7 进一步优化了淘汰算法(如 LFU 精度提升、采样效率改进),若条件允许,建议升级以获得更平滑的驱逐体验。
- 合理设置 maxmemory + 开启 lazyfree + 选择合适的淘汰策略,让两者协同工作,实现内存管理与性能的最优平衡。