Redis 的 Key 过期数据删除策略是 Redis 内存管理的关键部分,它通过 两种主要策略 相结合的方式清理过期数据:
1. 被动删除(惰性删除 - Lazy Expiration)
工作原理:
-
当客户端尝试访问某个 Key 时,Redis 会先检查该 Key 是否已过期
-
如果过期,则立即删除并返回 nil(就像 Key 不存在一样)
-
如果未过期,则正常返回数据
优点:
-
CPU 友好,只在访问时消耗资源
-
简单直接,不影响未访问的 Key
缺点:
-
内存不友好,不访问的过期 Key 会一直占用内存
-
可能导致内存泄露(如果某些过期 Key 永不被访问)
2. 主动删除(定期删除 - Periodic Expiration)
工作原理 :
Redis 会周期性地(默认每秒 10 次)执行以下操作:
-
随机测试:从设置了过期时间的 Key 集合中随机选择 20 个 Key
-
检查过期:删除其中所有已过期的 Key
-
调整频率:如果超过 25% 的 Key 已过期,则重复步骤 1-2
-
限制时间:每次扫描最多持续 25ms,避免阻塞主线程
配置参数(redis.conf):
conf
# 每秒执行过期扫描的次数(默认 10)
hz 10
# 每次扫描的 CPU 时间百分比上限(默认 25%)
# 实际上每次扫描最多 25ms(1000ms/hz * 25%)
优点:
-
减少内存中过期 Key 的堆积
-
在 CPU 和内存之间取得平衡
缺点:
-
不是实时的,可能存在过期 Key 未被及时清理
-
增加了一定的 CPU 开销
3. 内存淘汰策略(Eviction Policies)
当内存达到 maxmemory 限制时,Redis 会根据配置的策略删除数据:
conf
# 内存限制(默认不限制)
maxmemory <bytes>
# 淘汰策略
maxmemory-policy <policy>
淘汰策略选项:
| 策略<policy> | 描述 | 适用场景 |
|---|---|---|
| noeviction | 不淘汰,返回错误 | 数据绝对不能丢失 |
| allkeys-lru | 从所有 Key 中使用 LRU | 需要缓存效果 |
| volatile-lru | 从带过期时间的 Key 中使用 LRU | 混合使用 |
| allkeys-random | 随机删除所有 Key | 所有 Key 同等重要 |
| volatile-random | 随机删除带过期时间的 Key | 混合使用 |
| volatile-ttl | 删除即将过期的 Key(TTL最小) | 优先保留新数据 |
| allkeys-lfu | 从所有 Key 中使用 LFU(4.0+) | 访问频率重要 |
| volatile-lfu | 从带过期时间的 Key 中使用 LFU(4.0+) | 混合使用 |
4. 实际工作流程示例

5. 性能优化建议
-
监控过期 Key 数量:
bash # 查看过期 Key 相关信息 redis-cli info stats | grep expired_keys -
合理配置:
conf # 根据负载调整 hz 值 hz 100 # 更高频率(更及时清理,更高CPU) hz 1 # 更低频率(更少CPU,可能堆积) -
避免大量 Key 同时过期:
python# 不好的做法:同时设置相同过期时间 for i in range(100000): redis.set(f"key:{i}", "data", ex=3600) # 好的做法:添加随机偏移 for i in range(100000): redis.set(f"key:{i}", "data", ex=3600 + random.randint(0, 300))
6. 特殊情况处理
-
AOF/RDB 持久化:
-
RDB:生成快照时,过期 Key 不会被保存
-
AOF :Key 过期时,会追加一条
DEL命令
-
-
主从复制:
-
主节点删除过期 Key 后,会向从节点发送
DEL命令 -
从节点不会主动删除过期 Key,只接受主节点指令
-
-
集群模式:
-
每个节点独立管理自己的过期 Key
-
迁移槽位时,过期信息一并迁移
-
总结
Redis 的过期删除策略是 惰性删除 + 定期删除 的组合拳:
-
惰性删除:保证访问的正确性
-
定期删除:减少内存浪费
-
内存淘汰:防止内存耗尽的最后防线
这种设计在 CPU 使用率、内存效率和实现复杂性之间取得了良好的平衡,使得 Redis 能够高效处理大量带有过期时间的 Key。