Redis 的过期删除机制主要通过以下两种策略及其底层数据结构实现:
1. 过期键存储:过期字典(Expires Dictionary)
- 数据结构:哈希表(Hash Table)
- 作用:存储所有设置了过期时间的键及其对应的过期时间戳(毫秒精度)。
- 键(Key):数据库中的键名(如
user:1000
)。 - 值(Value):该键的过期时间戳(如
1717027200000
表示 2024-05-30 00:00:00)。
- 键(Key):数据库中的键名(如
- 操作示例:
EXPIRE user:1000 3600 # 设置键 user:1000 在 3600 秒后过期
2. 过期删除策略
Redis 通过 惰性删除 和 定期删除 两种策略协同工作,确保过期键被及时清理。
(1) 惰性删除(Lazy Expiration)
- 触发时机:在访问某个键时(如
GET user:1000
),Redis 会先检查该键是否过期。 - 实现逻辑:
def get_key(key): if key in expires_dict and expires_dict[key] < current_time: delete_key(key) # 删除过期键 return None return data_dict[key] # 返回键的值
- 优点:对 CPU 友好,仅在访问时触发删除操作。
- 缺点:若过期键长期不被访问,会占用内存(内存泄漏风险)。
(2) 定期删除(Active Expiration)
- 触发时机:Redis 周期性随机抽取部分键检查过期状态(默认每秒 10 次,可通过
hz
配置调整)。 - 实现逻辑:
- 从过期字典中随机选择
N
个键(N
可配置,默认 20)。 - 删除其中已过期的键。
- 若本轮删除的过期键占比超过
25%
,则重复步骤 1-2,直到比例低于 25% 或超时。
- 从过期字典中随机选择
- 优点:主动清理内存,减少未访问过期键的堆积。
- 缺点:需平衡 CPU 和内存占用(高频检查会增加 CPU 负载)。
3. 底层数据结构对比
策略 | 数据结构 | 特点 |
---|---|---|
过期字典 | 哈希表 | 快速查找键的过期时间,时间复杂度 O(1)。 |
定期删除 | 随机抽样+遍历 | 避免全表扫描,通过概率性抽样控制 CPU 消耗。 |
4. 为什么不用时间轮或优先级队列?
- 时间轮(Timing Wheel):
适合高频、精确的定时任务(如网络超时),但 Redis 过期键数量可能极大,维护时间轮会占用过多内存。 - 优先级队列(Heap):
按过期时间排序虽能快速找到最近过期的键,但插入/删除操作的时间复杂度为 O(logN),而 Redis 的随机抽样策略在平均场景下更高效。
redis短时间就有大量的数据存入,短时间又有大量数据失效,用时间轮则会因为维护时间轮占用大量内存,用优先级队列则会因为频繁的插入新数据导致cpu飙升
总结
Redis 的过期删除机制依赖 过期字典(哈希表) 存储键的过期时间,通过 惰性删除 和 定期删除 协同工作:
- 惰性删除:保证单次操作的高效性。
- 定期删除:平衡内存清理与 CPU 消耗。
这种设计在内存占用、CPU 负载和实现复杂度之间取得了较好的平衡。