一、基础定义
内存淘汰:Redis 内存达到maxmemory阈值时,主动删除 key 释放内存;在processCommand()处理命令时触发performEvictions()执行淘汰 ,Lua 脚本执行期间不会做淘汰。 配置项:maxmemory-policy,默认 noeviction
二、8 种淘汰策略
表格
| 策略 | 淘汰范围 | 规则 |
|---|---|---|
| noeviction | 全部 key | 不淘汰,内存满直接拒绝写请求,默认策略 |
| volatile-ttl | 仅带 TTL 的 key | 剩余 TTL 越小,优先淘汰 |
| allkeys-random | 全部 key | 随机删 key |
| volatile-random | 仅带 TTL 的 key | 在过期 key 集合里随机删 |
| allkeys-lru | 全部 key | 淘汰最近最少使用 |
| volatile-lru | 仅带 TTL 的 key | 在带 TTLkey 里淘汰最近最少使用 |
| allkeys-lfu | 全部 key | 淘汰访问频次最低(Redis4.0+) |
| volatile-lfu | 仅带 TTL 的 key | 在带 TTLkey 里淘汰访问频次最低 |
区分:
- LRU:Least Recently Used,最近最少使用,robj 里 24bit 记录最后访问时间;时间差越大越优先淘汰
- LFU:Least Frequently Used,访问频次最低,robj 高位记录访问时间、低 8bit 存逻辑计数
三、RedisObject 存储 LRU/LFU 字段
typedef struct redisObject {
unsigned type:4; // 对象类型
unsigned encoding:4; // 底层编码
unsigned lru:LRU_BITS;
// LRU:24bit,秒级,记录最后访问时间
// LFU:高16bit分钟级时间,低8bit逻辑访问次数
int refcount; // 引用计数
void *ptr; // 数据指针
} robj;
LFU 逻辑计数(重点面试)
不是访问一次 + 1,是概率递增,还会衰减:
- 生成 0~1 随机数 R
- 计算阈值
P = 1/(旧次数 * lfu_log_factor +1),默认lfu_log_factor=10 R < P,计数器 + 1,上限 255- 衰减:每
lfu_decay_time(默认 1 分钟),计数器 - 1
四、淘汰执行流程(流程图要点)
- 写命令进来,判断内存是否充足;充足直接放行
- 内存不足:判断策略是
noeviction→ 直接报错拒绝写入 - 非 noeviction:
- 随机策略:直接随机选 key 删除
- LRU/LFU/TTL:
- 循环遍历所有 DB,每次随机采样
maxmemory_samples个 key - 计算 idleTime,放入
eviction_pool候选池 - 候选池按 idleTime 升序,选出最该淘汰的 key 删除
- 循环遍历所有 DB,每次随机采样
- 循环执行,直到释放内存满足要求