Redis 过期删除策略+缓存淘汰策略
Redis 过期删除策略
在介绍 Redis 的过期删除机制之前,需要先说明:
定时删除、惰性删除、定期删除是对过期数据清理思路的抽象划分,用于分析不同策略在 CPU 开销与内存占用之间的取舍。实际的高性能缓存系统通常不会采用其中某一种,而是进行组合设计。
常见的过期删除策略
1. 定时删除
定时删除指的是:
当键到达过期时间的瞬间立即删除该键。
其实现通常需要:
- 为每一个设置了过期时间的 key 维护独立的定时事件(如定时器或最小堆)
- 到期后触发删除回调
优点:
- 过期键能够被及时清理
- 内存利用率高
缺点:
- 定时事件数量与过期 key 数量近似线性相关
- 当过期 key 较多时,定时回调会占用大量 CPU
- 严重影响主线程吞吐量
因此,Redis 并未采用这种高精度但高成本的策略。
2. 惰性删除
惰性删除的核心思想是:
不主动删除过期 key,仅在访问时检查其是否过期。
执行流程:
- 客户端访问 key
- Redis 判断 key 是否已过期
- 若已过期,立即删除并返回 key 不存在
优点:
- 对 CPU 非常友好
- 不做无意义的主动扫描
缺点:
- 如果某些 key 长期不被访问,即使已经过期,也会一直占用内存
- 单独使用会造成内存浪费
3. 定期删除(主动过期)
定期删除是 Redis 的后台主动清理机制:
- Redis 后台周期性执行过期扫描
- 随机抽样一部分设置了过期时间的 key
- 删除其中已经过期的 key
- 执行时间受
hz配置与时间片限制
需要注意:
- 并非全量扫描
- 并非严格“到点即删”
- 本质是一种近似清理机制
Redis 的过期删除策略总结
Redis 并未采用定时删除,而是通过以下组合方式清理过期 key:
惰性删除 + 定期删除(主动过期)
该组合策略在保证访问语义正确性的前提下:
- 避免定时删除带来的高 CPU 开销
- 防止惰性删除导致的大量过期 key 长期占用内存
Redis 的过期删除机制几乎不可精调,只能通过
hz和active-expire-effort间接控制后台主动过期的执行频率和强度;惰性删除行为本身不可配置。
Redis 缓存淘汰策略
缓存淘汰策略与过期删除策略的目标和触发条件不同,二者不能混淆。
1 | # 所有实践省流如下: |
与过期删除策略的区别
1. 作用范围不同
- 过期删除策略:
仅作用于设置了过期时间且已经过期的 key - 缓存淘汰策略:
作用于尚未过期但需要被移除的 key
可仅限于设置了过期时间的 key,或作用于所有 key
已经过期的 key 不会进入缓存淘汰流程,而是直接被删除。
2. 触发时机不同
- 过期删除策略:
- 访问 key 时触发(惰性删除)
- 后台周期性触发(定期删除)
- 缓存淘汰策略:
- 仅在配置了
maxmemory - 且内存使用达到上限时触发
- 仅在配置了
Redis 支持的内存淘汰策略
在 64 位系统上,Redis 默认不限制内存(
maxmemory=0),因此不会触发内存淘汰机制。
只有在显式设置maxmemory后,Redis 才可能在内存达到上限时,根据配置的淘汰策略执行缓存淘汰。
Redis 提供以下内存淘汰策略:
noeviction(默认)
不进行内存淘汰,写命令在内存不足时直接返回错误,读操作不受影响volatile-random
从设置了过期时间的 key 中随机淘汰volatile-ttl
优先淘汰剩余 TTL 较小的 key(近似实现)volatile-lru
从设置了过期时间的 key 中,淘汰最久未使用的 key(近似 LRU)volatile-lfu
从设置了过期时间的 key 中,淘汰使用频率最低的 key(近似 LFU)allkeys-random
从所有 key 中随机淘汰allkeys-lru
从所有 key 中淘汰最久未使用的 key(近似 LRU)allkeys-lfu
从所有 key 中淘汰使用频率最低的 key(近似 LFU)
查看与修改内存淘汰策略
查看当前淘汰策略:
1 | CONFIG GET maxmemory-policy |
修改方式:
- 运行时修改(立即生效,重启失效):
1 | CONFIG SET maxmemory-policy <policy> |
- 修改配置文件(重启后生效):
1 | maxmemory-policy <policy> |
运行时配置用于即时调整行为,配置文件用于持久化配置,二者配合可保证实例行为一致。
Redis 中 LRU 的实现机制
传统 LRU 通常通过双向链表实现,能够精确淘汰最久未使用的元素,但需要额外维护链表结构,成本较高。
Redis 并未维护全局 LRU 链表,而是采用近似 LRU 算法:
- 每个 key 记录最近一次访问时间
- 内存淘汰时,随机抽取 N 个 key
- 从样本中淘汰访问时间最早的 key
采样数量由参数 maxmemory-samples 控制:
- 样本数越大,淘汰结果越接近真实 LRU
- 默认值为 5,可按需调整
Redis 中 LFU 的实现机制
LFU 用于淘汰使用频率最低的 key。
Redis 的 LFU 实现同样是近似算法:
- 每个 key 维护访问频率计数
- 计数并非简单递增,而是概率性增长
- 同时引入时间衰减机制,避免历史热点永久占优
- 内存淘汰时,采用“随机抽样 + 比较频率”的方式选择淘汰目标
总结
- Redis 通过惰性删除 + 定期删除清理过期 key(过期删除策略)
- 缓存淘汰仅在配置
maxmemory且内存达到上限时触发、有八种(缓存淘汰策略) - 过期删除针对过期键、缓存淘汰针对未过期键但设置了过期时间的键+未设置过期时间的键
- tips:如果缓存淘汰时采样到的数据中有已经过期的键呢?那么算是缓存淘汰吗?
- 不是!会直接删除,不属于缓存淘汰的范围中。
- LRU / LFU 在 Redis 中均为近似实现,可通过采样参数进行调优





