https://chat.deepseek.com/share/36wxrdp1of9r7avbcg
面试记录 2026-09-20
题目:Redis的内存淘汰策略是怎么样的?
难度:medium
标签:db/redis/memory, general/knowledge
评分:⭐⭐⭐⭐☆(4/5)
我的回答
Redis 内存淘汰策略主要是应对于当它内存快满或者是已经满了的情况下的,应对于新的请求,新的存入,这时候有什么处理?如果是读取,它不会触发这个问题。然后首先是按是否设置的过期时间,设置过期时间的情况下,是一种淘汰策略选择,没设置过期时间的是一种淘汰策略选择划分,然后对应选择了相应的处理算法,LRU、LFU,然后随机三种,这加起来基本上就是 6 种淘汰处理方式。另外是还有默认处理策略,也就是抛返回错误,如果内存不够了,就直接也不处理,原来的也不动,直接就返回错误。大概是这么 7 种内存淘汰策略,分别是设置了时间的,好,设置了过期时间,然后 LRU、LFU 随机三种,未设置过过期时间全量的 LRU、LFU 随机三种,加上一种静默处理,也就抛出异常,不是静默处理。
点评
优点:
- 框架正确:抓住"过期时间维度 × 算法维度"的正交划分,7 种策略矩阵清晰
- 知道默认行为:noeviction 是默认策略,内存满直接返回错误
- 区分读写:只有写操作(新插入)触发淘汰,读不触发
- 主动修正自己("静默处理"→"抛出异常"),体现技术准确性意识
不足:
- 未说出策略具体名称:volatile-lru、volatile-lfu、volatile-ttl、volatile-random、allkeys-lru、allkeys-lfu、allkeys-random、noeviction
- 未提实现细节:LRU 是近似 LRU(采样 5 个候选)、LFU 是 Redis 4.0+ 新增(15-bit 计数器 + 时间衰减)、volatile-ttl 淘汰剩余 TTL 最小的
- 未给工程建议:allkeys-lru 通用、allkeys-lfu 适合热点长尾、noeviction 会让写失败
- 最后表述混乱:"静默处理→抛出异常"前后矛盾
补充:
- 8 种策略完整列表:noeviction / allkeys-lru / volatile-lru / allkeys-lfu / volatile-lfu / allkeys-random / volatile-random / volatile-ttl
- LRU 是近似的:采样 maxmemory-samples(默认 5)个候选选最老淘汰
- LFU 算法:15-bit 计数器,10 秒衰减周期,长期不访问计数归零
- 选型建议:缓存场景 allkeys-lru;热点长尾 allkeys-lfu;需保留数据 volatile-lru
- 监控:INFO stats 看 evicted_keys;CONFIG GET maxmemory-policy 查当前策略
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对 maxmemory-policy 8 种策略的正交矩阵理解,以及 LRU/LFU 底层实现。
知识点拆解:
- 术语区分:过期策略(TTL 到期删除 key,与内存无关)vs 内存淘汰策略(内存达 maxmemory 时腾空间,只在写操作触发)
- 8 种策略矩阵(两个正交维度):
- 范围维度:allkeys-(无差别淘汰)/ volatile-(只在有 EXPIRE 的 key 里淘汰)
- 算法维度:noeviction(默认,写失败)/ random / lru / lfu(4.0+)/ ttl(剩余 TTL 最小)
- 组合成 8 种:allkeys-lru、allkeys-lfu、allkeys-random、volatile-lru、volatile-lfu、volatile-random、volatile-ttl、noeviction
- LRU 是「近似 LRU」:维护链表 + Hash 开销大;采样淘汰,随机抽 maxmemory-samples(默认 5)个候选选最老,误差约 1%
- LFU 是「近似 LFU」——Redis 4.0+:15-bit 计数器记录访问频率,默认 10 秒衰减一次;优势是防新数据挤走真正热点
- noeviction 的坑:默认策略,内存满后所有写返回 OOM 错误;生产必须显式配置
- 实现机制:每次写命令前检查 used_memory > maxmemory;淘汰与过期是两个独立机制
- 工程实践:缓存场景 allkeys-lru(通用);热点长尾 allkeys-lfu;保留数据 volatile-lru
- 常见误区:LRU 是严格 LRU(错,是采样);LFU 3.0 就有(错,4.0);淘汰和过期是一回事(错);默认 allkeys-lru(错,是 noeviction)
第二部分:考察方向与延伸递进
考察方向:
- 深度:activeExpireCycle 采样逻辑?maxmemory-samples 调优?
- 广度:与 Memcached(无淘汰策略,只做 eviction allkeys-lru)对比
- 应用:热点分布长尾场景、缓存雪崩预警、evicted_keys 告警
延伸递进面试题:
- LRU 的采样淘汰为什么不是严格 LRU?
- 解答要点:维护链表 + Hash 开销大;采样误差可控(默认 5 个误差 ~1%)
- LFU 的时间衰减如何实现?
- 解答要点:15-bit 计数器,10 秒衰减周期,lfu-log-freq-factor 调参
- 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 对淘汰策略有什么优化?
- 解答要点:LFU 衰减优化;淘汰逻辑与过期逻辑解耦
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,Redis 内存淘汰策略是两个维度的正交组合:一个是范围(全部 key 还是只有有过期时间的 key),一个是算法(无 / 随机 / LRU / LFU / TTL)。加起来共 8 种。
范围维度:allkeys- 无差别淘汰;volatile- 只在设置了 EXPIRE 的 key 里淘汰。
算法维度:noeviction(默认)内存满直接写失败,返回 OOM 错误;random 随机删;lru 近似 LRU,采样 5 个候选选最老;lfu 近似 LFU,Redis 4.0+,基于 15-bit 计数器 + 时间衰减;ttl 优先淘汰剩余 TTL 最小的。
两个维度组合成 8 种:allkeys-lru、allkeys-lfu、allkeys-random、volatile-lru、volatile-lfu、volatile-random、volatile-ttl、noeviction。
LRU 是近似的,不是严格 LRU。严格 LRU 要维护双向链表和 Hash,开销大。Redis 用采样淘汰,随机抽 5 个候选,误差约 1%。可以调 maxmemory-samples 提升精度。
LFU 是 Redis 4.0 新增,适合热点分布长尾的场景。用 15-bit 计数器记录访问频率,默认 10 秒衰减一次,防止新数据挤走真正的热点。
noeviction 是默认策略,内存满直接返回错误。生产环境必须显式配置,不能让它扛。
我们项目用 allkeys-lru,因为业务里大部分 key 都有 TTL,且热点分布比较均匀。监控 INFO stats 的 evicted_keys,一旦突增就排查是不是 maxmemory 设小了或者数据量暴涨。
踩过一个坑:某次上线后 evicted_keys 每分钟涨几千,查下来是新版本把某些大 key 的 TTL 从 24h 改成了永不过期,导致 volatile-* 策略失效,触发全量淘汰。改回 TTL 就好了。所以淘汰策略 + TTL 设计要配套看,不能只改一边。