Redis 的 Key 过期后不会立即被删除。Redis 采用了一种结合 惰性删除 (Lazy Expiration) 和 定期删除 (Periodic Expiration) 的策略来管理过期 Key 的回收,这是为了在内存管理、性能和 CPU 开销之间取得平衡。
📌 Redis 过期 Key 删除的两种策略
🔍 1. 惰性删除 (Lazy Expiration)
- 触发时机:当客户端尝试访问一个 Key 时,Redis 会先检查这个 Key 是否已过期。
- 执行过程:
- 如果 Key 已过期,Redis 会立即删除它,并返回
nil
给客户端(就像这个 Key 不存在一样)。 - 如果 Key 未过期,则正常返回其值。
- 如果 Key 已过期,Redis 会立即删除它,并返回
- 优点:
- CPU 友好:只在访问时检查,不占用额外 CPU 资源扫描过期 Key。
- 简单高效:对未过期的 Key 没有额外开销。
- 缺点:
- 内存可能未及时释放:如果某个过期 Key 长时间不被访问,它会一直占用内存,直到被访问或通过定期删除被清理。这可能导致内存浪费(内存泄漏假象)。
⏰ 2. 定期删除 (Periodic Expiration / Probabilistic Algorithm)
- 触发时机:Redis 会 周期性 地(默认每秒运行 10 次,可通过
hz
配置调整)随机抽取一部分设置了过期时间的 Key 进行检查。 - 执行过程:
- 从设置了过期时间的 Key 集合中,随机抽取 一定数量的 Key(数量由配置控制)。
- 检查这些被抽中的 Key 是否过期。
- 删除所有已过期的 Key。
- 如果本轮抽查中过期 Key 的比例 超过 25%,则立即重复步骤 1(继续抽查并删除),直到比例低于 25% 或达到时间/次数限制。
- 优点:
- 减少内存浪费:即使 Key 不被访问,也有机会被清理掉。
- 可控的 CPU 开销:通过控制抽查频率 (
hz
) 和每次抽查的数量,可以限制对 CPU 的影响。
- 缺点:
- 非实时:过期 Key 不会在过期那一刻被立即删除,会有一定的延迟(通常在秒级)。
- 可能遗漏:如果过期 Key 比例很低或运气不好没被抽中,可能暂时不会被删除。
📊 总结:Key 何时会被删除?
场景 | 删除机制 | 延迟性 |
---|---|---|
Key 过期后被访问 | 惰性删除立即删除 | 实时(访问时触发) |
Key 过期后未被访问,但被定期删除抽中 | 定期删除清理 | 秒级延迟(取决于抽查频率和运气) |
Key 过期后长期未被访问且未被抽中 | 可能滞留内存 | 不确定(直到被访问或抽中) |
⚠️ 注意事项与影响
- 内存占用:大量过期 Key 未被及时删除会导致 Redis 实际内存使用量高于有效数据量。监控时需关注
expired_keys
(累计删除数) 和evicted_keys
(因内存不足被淘汰数) 指标。 - 内存淘汰策略:如果 Redis 配置了
maxmemory
且内存不足,即使 Key 未过期也可能根据策略(如allkeys-lru
)被淘汰。而过期 Key 滞留会加速触发内存淘汰,可能导致有用的 Key 被误删。 - 性能影响:定期删除的 CPU 开销取决于
hz
设置和过期 Key 数量。过高频率的抽查会增加 CPU 负担。 - 命令影响:像
KEYS *
或SCAN
命令可能会返回已过期但尚未被删除的 Key(但在返回前会触发惰性删除)。
🛠️ 如何应对过期 Key 滞留问题?
- 监控告警:监控 Redis 的
used_memory
、expired_keys
、evicted_keys
等指标,设置内存使用阈值告警。 - **调整
hz
**:适当增加hz
值(如从 10 调整到 100)可提高定期删除频率,加速清理过期 Key,但会增加 CPU 负载(需权衡)。 - 避免大量 Key 同时过期:对大量 Key 设置过期时间时,添加随机因子(如
TTL = base + random(0, 300)
),防止集中过期导致内存陡增或定期删除压力大。 - 使用
MEMORY PURGE
命令 (Redis 4.0+):手动触发内存清理(非标准命令,部分云服务商支持)。 - 升级 Redis 版本:新版 Redis 在内存管理和过期策略上可能有优化(如 Redis 6.0 的惰性删除线程)。
💎 结论
Redis 为了性能牺牲了过期 Key 删除的实时性。理解其 惰性删除 + 定期删除 的组合策略,对于诊断内存异常、优化配置和保障系统稳定性至关重要。务必监控内存指标,并根据业务场景调整相关参数。