真实面经题目 · 原创解析
Redis的过期策略?
Redis 的过期策略本质上是在性能、内存回收及时性和主线程延迟之间做平衡:它不会为每个带 TTL 的键单独启动定时器,而是通过 TTL 元数据记录过期时间,再结合访问时惰性删除和后台周期性主动抽样删除来清理过期键。回答时要区分过期删除与内存淘汰,并补充持久化、复制、过期风暴和热 Key 场景下的工程治理。
真实面经题目 · 原创解析
Redis 的过期策略本质上是在性能、内存回收及时性和主线程延迟之间做平衡:它不会为每个带 TTL 的键单独启动定时器,而是通过 TTL 元数据记录过期时间,再结合访问时惰性删除和后台周期性主动抽样删除来清理过期键。回答时要区分过期删除与内存淘汰,并补充持久化、复制、过期风暴和热 Key 场景下的工程治理。
Redis 给 Key 设置过期时间后,会在内部维护一份过期字典,记录 Key 和绝对过期时间戳。它的删除策略不是单纯的定时删除,因为为大量 Key 维护定时器会带来很高的 CPU 和调度成本;也不是只等访问时删除,因为冷 Key 可能长期占用内存。因此 Redis 采用惰性删除加主动删除的组合策略。惰性删除发生在读写访问 Key 时,Redis 会先检查该 Key 是否已经过期,过期则删除并返回不存在;主动删除则由周期任务定期从设置了过期时间的 Key 中抽样检查,删除已过期的 Key,并根据过期比例、时间预算等条件决定是否继续扫描。这样能在不阻塞主线程太久的前提下回收大部分过期数据。还要注意,过期策略和内存淘汰策略不是一回事:过期策略处理 TTL 到期的 Key,而淘汰策略是在内存达到 maxmemory 限制时,根据 allkeys-lru、volatile-lru、allkeys-lfu、volatile-ttl、noeviction 等策略选择牺牲对象。工程上需要避免大量 Key 同一时刻过期造成删除压力和缓存穿透,可以给 TTL 增加随机抖动,热点数据采用续期、逻辑过期或异步重建;同时关注 RDB、AOF 和主从复制下过期删除的传播行为,保证一致性和恢复后的数据语义。
Redis 不会把过期时间直接作为 Value 的一部分保存,而是通过额外的过期字典维护 Key 到过期时间戳的映射。判断是否过期时,Redis 比较当前时间与该时间戳,因此同一个 Key 的值数据和过期元数据是分开管理的。
客户端访问 Key 时,Redis 先检查它是否设置了 TTL 且已经到期,如果到期就删除该 Key 并按不存在处理。这种方式成本低,只有真实访问时才付出判断和删除成本,但无法主动处理长期不被访问的冷 Key。
Redis 会周期性从设置过期时间的 Key 集合中抽样,删除已经过期的 Key,并在过期比例较高时继续循环,避免过期 Key 大量堆积。主动过期不是全量扫描,而是带抽样和时间预算的近似清理。
为每个 Key 创建独立定时任务会造成调度和 CPU 开销,尤其在高并发缓存场景下不可控。Redis 选择惰性删除与主动抽样结合,是用近似及时性换取整体吞吐稳定和主线程延迟可控,同时避免过期键规模大时被海量定时回调拖垮。
TTL 到期不代表 Key 会在同一毫秒被物理删除,未访问且未被主动抽样命中的 Key 可能延迟回收。但从访问语义上看,Redis 会在访问时判断过期并删除,因此客户端看到的是不存在。
过期删除由 TTL 触发,目标是已经到期的 Key;内存淘汰由 maxmemory 触发,目标是在内存压力下释放空间。即使 Key 未过期,内存紧张时也可能被淘汰;即使内存充足,过期 Key 仍然应该被清理。
volatile 类策略只在设置了过期时间的 Key 中选择淘汰对象,allkeys 类策略在全量 Key 中选择。volatile-ttl 倾向淘汰剩余 TTL 更短的 Key;业务如果把 Redis 完全当缓存用,allkeys-lru 或 allkeys-lfu 通常更贴近预期。
大量 Key 在同一时间到期会造成集中删除、数据库回源激增和请求延迟抖动。常见治理方式是 TTL 随机化、分批预热、限流、熔断和异步重建,让过期和回源压力在时间上摊开,避免缓存层和数据库同时承受尖峰流量。
热点 Key 如果突然过期,可能导致大量请求同时穿透到后端。可使用逻辑过期、互斥锁重建、后台续期、单飞合并请求等方式降低冲击,保证只有少量请求负责重建缓存,其余请求复用旧值或等待重建结果。
RDB 保存时通常不会写入已经过期的 Key,AOF 会记录删除语义;主从复制中通常由主节点判定过期并向从节点传播删除,避免不同节点各自删除导致不一致。恢复和复制语义是 Redis 过期策略的高阶考点。
需要结合内存水位、expired_keys、evicted_keys、命中率、延迟监控和业务 TTL 分布来设计缓存生命周期,而不是只会背惰性删除和定期删除。线上还要观察过期集中度和回源压力。
纯定时删除需要为每个带 TTL 的 Key 维护触发点,大量 Key 会带来调度成本和 CPU 压力,影响主线程处理请求,所以 Redis 采用近似、分批、带时间预算的方式。
不一定。到期只是语义上失效,物理删除依赖访问触发或主动抽样命中,因此冷 Key 可能延迟释放。不过一旦访问它,Redis 会先判断过期并按不存在处理。
expire 处理 TTL 到期;淘汰处理内存达到限制。前者由时间触发,后者由内存压力触发,两者可以同时存在但不是同一机制。
给 TTL 增加随机抖动,按批次预热,热点数据使用逻辑过期或后台刷新,并对回源链路加限流、熔断和互斥重建,让缓存失效和数据库回源压力被摊开。
通常由主节点负责过期判断并向从节点传播删除命令,从节点不独立决定删除时机,以减少主从不一致风险。这样可以避免不同机器时间和抽样节奏差异导致读到不同结果。
如果只希望淘汰设置了 TTL 的缓存数据,可以选 volatile-lru;如果整个 Redis 实例都是缓存用途,allkeys-lru 通常更符合预期。