Redis 作为高性能键值存储,其自动过期键(Key)的能力对管理内存至关重要。它并非依赖单一策略,而是巧妙地结合三种机制协同工作,确保过期数据被及时清理。下面我们深入解析其工作原理。
核心机制:三种策略协同工作
-
定时删除 (Timing Delete - 主动精准型)
-
原理: 当为键设置过期时间(TTL)时,Redis 同时创建一个定时器。一旦键的生存时间耗尽,定时器触发,立即删除该键。
-
优点: 过期键能被最快、最精确地删除,内存释放及时。
-
缺点: 创建和管理大量定时器本身消耗 CPU 时间和内存资源。如果一个键设置了很长的 TTL 但实际很快不再需要,定时器会持续占用资源直到触发。因此,Redis 不会对每一个设置了 TTL 的键都使用定时删除。
-
适用场景: Redis 内部对极少数需要精确控制删除时间的场景(如某些内部管理键)可能使用,但不是主流策略。
-
-
惰性删除 (Lazy Delete - 被动触发型)
-
原理: 不主动扫描或检查键是否过期。只有当客户端尝试访问某个键时,Redis 在执行命令前才会检查该键的过期时间。
-
如果键已过期:Redis 立即删除该键,并返回空值(nil)给客户端(仿佛键不存在)。
-
如果键未过期:正常执行命令。
-
-
优点:
-
CPU 开销最小化: 只在访问时检查,避免了无谓的扫描消耗。
-
简单高效: 实现直接,对未访问的过期键无额外负担。
-
-
缺点:
-
内存可能未及时释放: 如果一个键过期后再也没有被访问,它将一直占用内存,成为“僵尸键”,直到被其他策略清理或 Redis 重启。这是内存浪费的主要来源。
-
-
核心地位: 这是 Redis 最基础、最常用的过期处理策略,所有访问命令都会触发惰性检查。
-
-
定期删除 (Periodic Delete - 主动扫描型)
-
原理: Redis 会周期性地(默认每秒执行 10 次,可配置)运行一个任务。每次任务并非扫描所有键,而是:
-
随机抽取一定数量(由
hz
配置参数间接影响)的设置了过期时间的键。 -
检查这些被抽中的键是否过期。
-
删除所有已过期的键。
-
如果本次抽查中发现过期键的比例超过一定阈值 (25%),则立即再随机抽取一批进行检查删除(循环),直到过期键比例低于阈值或达到时间/数量限制,确保不会过度阻塞主线程。
-
-
优点:
-
折中方案: 在 CPU 开销(主动扫描)和内存释放及时性(惰性删除的缺点)之间取得平衡。
-
清理“僵尸键”: 专门负责清理那些过期了但没被访问到的键,解决惰性删除的主要缺陷。
-
可配置性: 通过调整
hz
参数(控制后台任务执行频率)可以影响定期删除的积极程度。
-
-
缺点:
-
非完全实时: 过期键不会在过期那一刻立刻被删除,会有一定延迟(通常很短,取决于扫描频率和键被抽中的概率)。
-
CPU 可控但有波动: 虽然通过随机抽样和比例阈值控制了 CPU 开销,但在过期键非常多时,一次扫描周期内可能需要连续多轮删除,可能引起短暂的 CPU 使用率升高。
-
-
三种策略如何协同工作?
-
设置过期: 当用户为键设置
EXPIRE
或PEXPIRE
时,Redis 记录其 TTL。 -
访问触发惰性删除: 任何对该键的后续访问(
GET
,HGET
,EXISTS
等)都会触发惰性检查,过期则立即删除。 -
定期扫描查漏补缺: 后台的定期删除任务不断运行,随机抽样检查并删除过期键,重点清理那些“无人问津”的过期键。
-
(补充)定时删除: 在极少数特定场景下内部使用。
总结与启示
-
核心是惰性+定期: Redis 高效管理过期键的核心在于 惰性删除 (Lazy Delete) 和 定期删除 (Periodic Delete) 的双剑合璧。惰性删除处理被访问的键,成本最低;定期删除清理未被访问的“僵尸键”,保证内存回收。
-
内存 vs CPU 的权衡: 惰性删除省 CPU 但可能浪费内存;定期删除回收内存但消耗 CPU;定时删除精准但开销大。Redis 选择了惰性+定期的组合,在绝大多数场景下达到了最佳平衡。
-
理解“非实时”: 由于定期删除的抽样机制和惰性删除的特性,Redis 不能保证键在过期时间到达的那一刻被立即删除。会有毫秒到秒级的延迟是正常现象。
-
配置影响: 增加
hz
值会让定期删除任务跑得更频繁,可能提高清理过期键的速度(减少延迟、更快释放内存),但也会略微增加 CPU 负担。通常默认值 (10
) 已足够。 -
与淘汰策略区分: 过期策略 (
expire
) 负责清理明确设置了 TTL 且已过期的键。当内存不足时,Redis 会启动内存淘汰策略 (maxmemory-policy
,如allkeys-lru
,volatile-ttl
等),它们的目标是在内存满时选择一些键(可能包括未过期的键)删除以腾出空间。两者目的和触发条件不同,但都服务于内存管理。
结论: Redis 的过期策略是精心设计的实用方案。它通过惰性删除处理日常访问,通过定期删除进行兜底清理,巧妙地平衡了内存利用率与 CPU 开销。理解其协同工作原理,有助于我们更好地使用 Redis 的 TTL 功能,构建更健壮的缓存和数据存储服务。对于大多数应用,默认配置已是最优选择。