TL;DR(30 秒扫完)
- 过期策略 = 惰性删除 + 定期删除(组合使用,不是独立线程)
- 淘汰策略 = 8 种 maxmemory-policy(范围 × 算法的正交矩阵)
- LRU 是近似的:采样 5 个候选选最老,不是严格 LRU
- LFU 是 Redis 4.0+:15-bit 计数器 + 10 秒时间衰减,防热点长尾
- 默认是 noeviction:内存满直接写失败,生产必须显式配置
关键结论
结论 A过期扫描是主线程
serverCron 定时任务,不是独立线程结论 B8 种淘汰策略 = 2 种范围(allkeys/volatile)× 4 种算法(无/随机/LRU/LFU/TTL)
结论 CLRU/LFU 都是"近似"的——维护链表+Hash 开销大,采样更划算
结论 D
volatile-* 策略如果可删 key 不够会返回错误,生产慎用完整讲解(费曼四步)
STEP 1 · 概念
过期策略:如何处理到达 TTL 的 key(Redis 只有两种机制组合) 淘汰策略:内存达到maxmemory 时如何腾空间(8 种策略)
两者独立但会同时发生(如 volatile-lru 既检查 TTL 又检查 LRU)。
STEP 2 · 大白话
过期策略比喻:- 惰性删除:快递过期了,有人来取才扔掉(访问时才检查)
- 定期删除:物业每天巡楼扔过期快递(主线程定时扫,但只扫一部分)
noeviction:柜子满了就不放新书(默认,写失败)allkeys-lru:柜子满了就扔最久没翻的书(全部 key 中淘汰 LRU)volatile-lru:柜子满了就扔有到期日且最久没翻的书(只在有 TTL 的 key 中淘汰)allkeys-lfu:柜子满了就扔翻得最少的书(基于访问频率)
STEP 3 · 底层
过期策略两大机制(组合使用)
① 惰性删除(Lazy Expiration)- 访问 key 时(
lookupKey阶段)判断expire < now - 过期就调
expireDictGenericDelete立即删除 - 优点:零开销(只有访问才触发)
- 缺点:冷门 key 永不被访问 → 内存一直占着
- 主线程定时器
serverCron(每秒约 10 次)触发activeExpireCycle - 每次从
expires字典随机抽 20 个有过期时间的 key - 统计这 20 个中实际过期的比例:
- 过期比例 ≤ 25%:本轮结束(说明整体过期不多)
- 过期比例 > 25%:继续循环,直到 CPU 时间超过 25ms 或扫完
- 优点:控制过期 key 数量,避免内存泄漏
- 缺点:采样有遗漏,个别 key 会晚删
- 单线程全扫会阻塞所有命令,延迟飙升
- 采样 + 时间限制是 CPU 与内存的折中
- 过期信息存
expires字典(key → unixtime ms),与db主字典分离 EXPIRE/PEXPIRE/SET EX写 expires 字典- 每次命令执行前后都可能触发一次
activeExpireCycle
内存淘汰策略 8 种(正交矩阵)
| 范围 | 淘汰算法 | 策略名 | 说明 |
|---|---|---|---|
| 全部 key | 无 | noeviction | 默认,写失败返回错误 |
| 全部 key | 随机 | allkeys-random | 从所有 key 随机删 |
| 全部 key | LRU | allkeys-lru | 从所有 key 淘汰最近最少使用 |
| 全部 key | LFU | allkeys-lfu | 从所有 key 淘汰最不经常使用 |
| 有过期时间的 key | 随机 | volatile-random | 只在有 TTL 的 key 中随机删 |
| 有过期时间的 key | LRU | volatile-lru | 只在有 TTL 的 key 中淘汰 LRU |
| 有过期时间的 key | LFU | volatile-lfu | 只在有 TTL 的 key 中淘汰 LFU |
| 有过期时间的 key | TTL | volatile-ttl | 优先淘汰剩余 TTL 最小的 |
allkeys-*:无论有没有过期时间都参与淘汰(缓存场景推荐)volatile-*:只在设置了 EXPIRE 的 key 中淘汰;如果这类 key 不够删,就返回错误
LRU 是「近似 LRU」——非严格 LRU
- 严格 LRU 需要维护双向链表 + Hash,开销大
- Redis 用采样淘汰:随机抽
maxmemory-samples(默认 5)个候选,选最老淘汰 - 默认采样 5 个误差约 1%,可配置 10-100 提升精度但增加开销
- 时间戳存在 key 的
lastAccessedTime字段(4 字节)
LFU 是「近似 LFU」——Redis 4.0+ 新增
- 15-bit 计数器存在 key 结构里,记录访问频率
- 计数器采用时间衰减:每 10 秒(
lfu-log-freq-factor控制)衰减一次 - 新 key 首次访问给初始值(默认 5)
- 优势场景:热点分布长尾时,防止新数据挤走真正的热点
noeviction 的坑
- 默认策略,内存满后所有写操作返回
OOM command not allowed when used memory exceeds 'maxmemory' - 生产环境必须显式配置淘汰策略,不能让默认值扛
- 业务层要处理这个错误(重试/降级)
选型建议
| 场景 | 推荐策略 | 原因 |
|---|---|---|
| 通用缓存 | allkeys-lru | 有 TTL 无 TTL 一起淘汰,不挑 |
| 热点长尾 | allkeys-lfu | 防新数据挤走真正热点 |
| 需要保留数据 | volatile-lru | 只淘汰有 TTL 的,但可能返回错误 |
| 会话缓存 | volatile-ttl | 优先淘汰剩余 TTL 最小的 |
| 数据安全优先 | noeviction | 写失败好过丢数据,但业务要处理 |
监控指标
INFO stats:
evicted_keys: 被淘汰的 key 数(内存驱动)
expired_keys: 过期的 key 数(TTL 驱动)
CONFIG GET maxmemory-policy # 查当前策略
STEP 4 · 简化
一句话总结:过期=惰性+定期(主线程定时扫),淘汰=8 种策略(范围×算法),LRU/LFU 都是近似的。 记忆口诀:- 过期:访问删 + 定时扫(20 个/25%/25ms)
- 淘汰:8 种 = 2 范围(allkeys/volatile)× 4 算法(无/随机/LRU/LFU/TTL)
- LRU:采样 5 个选最老
- LFU:15-bit 计数器 + 10 秒衰减
- 默认:noeviction(写失败)
常见误区
说"Redis 有专门的过期线程"
是主线程
serverCron 定时任务说"过期 key 立即删除"
不保证,采样机制有概率延迟
说"LRU 是严格 LRU"
是采样的近似 LRU,维护链表开销大
说"LFU 从 3.0 就有"
Redis 4.0 新增
说"淘汰和过期是一回事"
过期是 TTL 驱动,淘汰是内存驱动,两个独立机制
说"默认策略是 allkeys-lru"
默认是
noeviction延伸追问
activeExpireCycle 的具体逻辑?采样 20 个过期 key,过期比例 >25% 继续,单次最多 25ms;
serverCron 每秒 10 次 + 命令前后触发如何判断过期 key 堆积?
INFO keyspace 看 expired_keys;MEMORY USAGE 看内存;DBSIZE 与真实存活数对比volatile-lru 和 allkeys-lru 怎么选?有 TTL 的 key 占比高用 volatile-lru;混合场景用 allkeys-lru
evicted_keys 突增如何排查?INFO memory 看 used_memory vs maxmemory;INFO stats 看 evicted_keys 速率;确认是策略主动淘汰还是内存爆表Redis 7.0 对过期清理有什么优化?
过期清理的 CPU 时间控制更精细;
activeExpireCycle 支持按数据库独立触发maxmemory-samples 怎么调优?默认 5 误差约 1%;提高到 10-100 精度提升但开销增大;一般不改
速查表
过期: 惰性删除 + 定期删除(主线程 serverCron 定时扫)
定期扫: 20 个/次, 过期率 >25% 继续, 单次最多 25ms
淘汰: 8 种 = 2 范围(allkeys/volatile) × 4 算法(无/随机/LRU/LFU/TTL)
LRU: 近似, 采样 maxmemory-samples(默认 5) 个选最老
LFU: 近似, 15-bit 计数器 + 10 秒衰减, Redis 4.0+
默认: noeviction(写失败)
监控: INFO stats → evicted_keys / expired_keys
Anki 候选卡片
Q: Redis 过期策略的两个机制?
A: 惰性删除 + 定期删除(组合使用)
Q: 定期删除的采样参数?
A: 20 个/次,过期率 >25% 继续,单次最多 25ms
Q: Redis 内存淘汰策略有几种?
A: 8 种 = 2 范围(allkeys/volatile)× 4 算法(无/随机/LRU/LFU/TTL)
Q: LRU 是严格 LRU 吗?
A: 不是,是采样的近似 LRU,默认抽 5 个候选选最老
Q: LFU 从哪个版本开始支持?
A: Redis 4.0,15-bit 计数器 + 10 秒时间衰减
Q: Redis 默认淘汰策略?
A: noeviction(内存满写失败返回错误)
关联题目
- 《Redis 的过期策略是怎么样的?》— 2026-09-20 Round 1 Q5, ⭐⭐(误说独立线程,遗漏采样细节)
- 《Redis的内存淘汰策略是怎么样的?》— 2026-09-20 Round 1 Q6, ⭐⭐⭐⭐☆(框架正确,缺策略名称)
关联知识
过期是 TTL 驱动的删除,淘汰是内存驱动的选择性删除——两个独立机制
过期像快递过期自动销毁;淘汰像仓库满了只能扔掉最不重要的
✦ 记 忆 口 诀 ✦
过期=惰性+定期;淘汰=8 种策略(范围×算法矩阵)
关键可视化
过期 vs 淘汰两个独立机制
flowchart TB M["Redis 内存管理"] --> E["过期策略<br/>TTL 驱动"] E --> E1["惰性删除<br/>访问时才检查"] E --> E2["定期删除<br/>serverCron 抽样"] M --> V["淘汰策略<br/>maxmemory 触发"] V --> V1["2 种范围<br/>allkeys/volatile"] V --> V2["4 种算法<br/>无/随机/LRU/LFU/TTL"]
8 种淘汰策略矩阵
flowchart TB
subgraph 范围
R1["allkeys-*<br/>所有 key"]
R2["volatile-*<br/>带 TTL 的 key"]
end
subgraph 算法
A1["noeviction<br/>直接失败"]
A2["random<br/>随机"]
A3["lru<br/>最近最少用"]
A4["lfu<br/>最不常用"]
A5["ttl<br/>最短过期"]
end
R1 --> A1 & A2 & A3 & A4
R2 --> A1 & A2 & A3 & A4 & A5LFU 15-bit 计数器 + 10 秒时间衰减
flowchart LR
C["LFU 计数器<br/>15-bit"] --> T["时间衰减"]
T --> D["每小时 -1<br/>防热点长尾"]
subgraph 特点
P1["采样 5 个候选<br/>选最不常用"]
P2["Redis 4.0+<br/>默认 lfu"]
P3["比 LRU 更精确<br/>但开销稍大"]
end知识关系
⬆️ 前置(Prerequisite)
redis-single-thread🔄 延伸(Extends)
暂无
🎯 概念
📏 规则
⚠️ 误区
🔍 追问
✨ 口诀
共 0 张卡,点击翻面