Redis 的键过期删除策略与内存淘汰机制详解
一、键过期删除策略
Redis 通过 定期删除(Active Expire) 和 惰性删除(Lazy Expire) 两种方式结合,管理键的过期清理。
1. 惰性删除(Lazy Expire)
- 触发时机:当客户端尝试访问某个键时,Redis 会先检查该键是否过期。
- 执行逻辑:
if key.expired?delete_key(key)return nil elsereturn key.value end
- 优点:
- 对 CPU 友好,只在访问时检查,不占用额外资源。
- 缺点:
- 内存泄漏风险:如果键长期不被访问,即使过期也会一直占用内存。
2. 定期删除(Active Expire)
- 触发时机:Redis 周期性(默认每秒 10 次)随机抽取部分过期键检查并删除。
- 执行流程:
- 从过期字典中随机选择
N
个键(N
由hz
参数控制,默认 20)。 - 删除其中已过期的键。
- 如果过期键比例超过 25%,则重复步骤 1。
- 从过期字典中随机选择
- 优点:
- 减少内存泄漏概率,平衡 CPU 和内存占用。
- 缺点:
- 仍可能残留部分过期键(依赖随机抽样)。
二、内存淘汰机制(Eviction Policies)
当 Redis 内存达到 maxmemory
限制时,会根据配置的淘汰策略删除键,腾出空间。
1. 淘汰策略配置
在 redis.conf
中设置:
maxmemory <bytes> # 最大内存(如 4GB)
maxmemory-policy <policy> # 淘汰策略
2. 常见淘汰策略
策略 | 规则 | 适用场景 |
---|---|---|
noeviction (默认) | 拒绝所有写入操作(返回 OOM 错误),只允许读 | 数据绝对不允许丢失 |
allkeys-lru | 淘汰全体键中最近最少使用(LRU)的键 | 热点数据集中,长期冷数据可丢弃 |
volatile-lru | 仅淘汰设置了过期时间的键中的 LRU 键 | 需保留持久化数据,仅清理临时数据 |
allkeys-random | 随机淘汰全体键 | 无明确访问规律时 |
volatile-random | 随机淘汰设置了过期时间的键 | 临时数据可随机清理 |
volatile-ttl | 优先淘汰剩余存活时间(TTL)最短的过期键 | 需要快速清理即将过期的数据 |
allkeys-lfu (Redis 4.0+) | 淘汰全体键中访问频率最低(LFU)的键 | 长期冷门数据优先清理 |
volatile-lfu (Redis 4.0+) | 淘汰设置了过期时间的键中访问频率最低的键 | 临时冷数据优先清理 |
3. 策略选择建议
- 缓存场景:
allkeys-lru
或allkeys-lfu
(优先保留热点数据)。 - 混合数据:
volatile-lru
+ 对持久数据不设过期时间。 - 严格时效性:
volatile-ttl
(如会话缓存)。
三、工作流程总结
- 写入键时:
- 检查内存是否超限 → 若超限,触发淘汰机制。
- 读取键时:
- 惰性删除检查过期 → 若过期则删除。
- 后台周期任务:
- 定期删除抽样过期键。
四、调优注意事项
- 监控过期键:
redis-cli info stats | grep expired_keys # 查看已删除的过期键数量
- 避免集中过期:
- 大批量键设置相同过期时间会导致定期删除压力激增,应分散过期时间(如加随机偏移)。
- LFU 优化(Redis 4.0+):
- 通过
lfu-log-factor
和lfu-decay-time
调整频率计数器的灵敏度和衰减速度。
- 通过
总结
- 删除策略:惰性删除 + 定期删除互补,平衡实时性和资源开销。
- 淘汰机制:根据业务特点选择 LRU/LFU/TTL 等策略,避免内存溢出。
- 实践建议:监控内存和过期键,结合
maxmemory
和hz
参数优化性能。