# Redis 数据过期后的删除策略是什么?
8 min read
Table of Contents
Redis 数据过期后的删除策略是什么?
Redis 数据过期删除策略详解
【核心定义】
Redis 数据过期后的删除策略是一种结合了惰性删除和定期删除的复合型策略,旨在平衡内存使用效率与CPU性能消耗。
【关键要点】
-
惰性删除(Lazy Expiration)
- 结论:访问时检查并删除过期键。
- 原理:当客户端访问某个键时,Redis 会先检查该键是否已过期。如果过期,则立即删除并返回空值;如果未过期,则正常返回数据。这种策略将删除操作延迟到实际访问时,避免了不必要的CPU开销。
-
定期删除(Periodic Expiration)
- 结论:周期性抽样检查并删除过期键。
- 原理:Redis 会每隔一段时间(默认每秒10次)随机抽取一定数量的键(默认20个)进行检查。如果发现过期键,则删除;如果抽样中过期键比例超过25%,则继续抽样直到比例低于25%或达到时间上限。这种策略主动清理过期键,防止内存泄漏。
【深度推导/细节】
策略设计的核心矛盾
Redis 需要在 内存回收效率 与 CPU性能消耗 之间取得平衡:
- 如果只使用惰性删除,大量永不访问的过期键会长期占用内存(内存泄漏风险)
- 如果采用实时删除(每个键设置独立定时器),会产生巨大的定时器开销和上下文切换成本
复合策略的运作逻辑
Step 1 - 键设置过期时间时
- Redis 将键和过期时间存入过期字典(expires dict)
- 不立即安排删除任务,避免定时器爆炸
Step 2 - 客户端访问时(惰性删除触发)
def get(key): if key in expires_dict and expires_dict[key] < current_time: delete_key(key) # 立即删除 return None return data_dict[key]Step 3 - 定期任务执行时(Redis 内部循环)
def periodic_expire(): for i in range(20): # 默认抽样20个键 key = random_key_from_expires_dict() if is_expired(key): delete_key(key) expired_count += 1
# 启发式继续抽样逻辑 if expired_count / 20 > 0.25: # 过期比例超过25% continue_sampling() # 继续抽样直到比例下降或时间耗尽关键数字的合理性
- 每秒10次检查:平衡实时性与CPU消耗,10Hz的频率既能及时清理又不会过度占用CPU
- 每次20个键:抽样数量在统计意义上有代表性,同时单次操作耗时可控
- 25%阈值:当过期键比例高时,加大清理力度;比例低时停止,避免无效遍历
【关联/对比】
Redis vs 传统缓存系统的删除策略
| 策略类型 | Redis采用 | Memcached采用 | 优缺点对比 |
|---|---|---|---|
| 惰性删除 | ✓ | ✓ | 节省CPU,但可能内存泄漏 |
| 定期删除 | ✓ | ✗ | 主动清理,补充惰性删除不足 |
| 定时删除 | ✗ | ✗ | 实时性好但CPU开销大 |
Redis 不同版本优化
- Redis 2.8之前:定期删除可能因大量过期键导致服务阻塞
- Redis 2.8+:引入自适应算法,根据过期键密度动态调整抽样频率和数量
- Redis 4.0+:支持异步删除(lazyfree-lazy-expire),将大键删除放到后台线程,避免主线程阻塞
【线程安全考虑】
Redis 单线程模型保证了删除操作的原子性:
- 惰性删除在命令执行过程中同步完成
- 定期删除在事件循环的定时任务中执行
- 无需加锁,天然避免并发冲突
【内存保护机制】
当上述策略仍无法控制内存时,Redis 会触发内存淘汰策略(maxmemory-policy):
- volatile-lru:从已设置过期时间的键中淘汰最近最少使用的
- allkeys-lru:从所有键中淘汰最近最少使用的
- volatile-random:从已设置过期时间的键中随机淘汰
- allkeys-random:从所有键中随机淘汰
- volatile-ttl:从已设置过期时间的键中淘汰存活时间最短的
- noeviction:不淘汰,返回错误(默认策略)
『面试官追问』
-
如果大量键同时过期会怎样?
- Redis 4.0前可能出现请求延迟,因为定期删除会持续抽样直到过期比例下降
- Redis 4.0后可通过配置
active-expire-effort调整删除力度,或使用异步删除
-
过期时间精度是多少?
- 理论上精度为1毫秒,但实际删除可能延迟到下次定期检查或访问时
- 过期字典使用UNIX时间戳存储,精度足够但执行有延迟
-
如何保证分布式环境下时间同步?
- Redis 依赖服务器本地时间,集群中需要保证时间同步(使用NTP)
- 过期判断基于本地时钟,时钟回拨可能导致键提前或延迟删除
-
持久化时如何处理过期键?
- RDB:生成快照时过期键不会被保存
- AOF:键过期时记录一条DEL命令,加载时重新执行
- 主从复制:从库不主动删除,等待主库同步DEL命令
-
为什么不用真正的定时器?
- 定时器需要为每个键创建数据结构,内存开销大(每个定时器至少需要指针、时间值等)
- 高频率的定时器回调会导致上下文切换频繁,影响单线程性能
- Redis 的设计哲学是用空间换时间,但这里是用时间换CPU(允许少量内存滞留,换取更平稳的CPU使用)
这种复合策略体现了 Redis 在工程实践上的精妙平衡:既保证了大多数场景下的内存效率,又避免了极端情况下的性能抖动。