Skip to content

Redis的过期删除策略

1. 惰性删除 (Lazy Deletion)

惰性删除是指 Redis 在客户端访问一个键时,会先检查这个键是否已经过期。如果过期,Redis 会立即删除这个键,然后返回空值;如果没过期,则正常返回值。

  • 优点:这种策略对 CPU 非常友好,因为它只在必要时才进行删除操作,不会在删除过期键上花费额外的 CPU 时间。
  • 缺点:对内存不友好。如果一个键过期后一直没有被访问,它就会一直占用着内存,不会被释放,这在某种程度上可能导致内存泄漏。

2. 定期删除 (Periodic Deletion)

由于惰性删除策略可能导致大量过期键积压在内存中,Redis 还引入了定期删除策略作为补充。

Redis 会每隔一段时间(默认是每秒 10 次),从设置了过期时间的键中随机抽取一部分进行检查,并删除其中已过期的键。这个过程由 activeExpireCycle 函数实现。 这是一个主动的删除过程,旨在清理那些可能永远不会被再次访问的过期键。

  • 优点:通过主动清理,可以有效减少因过期键堆积而造成的内存浪费。
  • 缺点:这是一个权衡策略。如果删除操作过于频繁或执行时间过长,会占用较多的 CPU 资源,影响服务器的响应性能。因此,Redis 的定期删除是随机且分批进行的,以控制其对 CPU 的影响。

3. Redis 采用的组合策略

为了在 CPU 性能和内存使用之间取得平衡,Redis 实际上是惰性删除和定期删除两种策略的结合

  • 通过定期删除,Redis 主动清理过期的键,在很大程度上回收了内存。
  • 通过惰性删除,Redis 确保了客户端在访问数据时绝对不会获取到已过期的内容。

这种组合策略使得 Redis 能够高效地管理过期键,既避免了大量内存的浪费,又不会对 CPU 造成过大的压力。

4. 主从复制中的过期处理

在主从复制结构中,从节点不会主动删除过期键。当主节点上的一个键过期时(无论是通过惰性删除还是定期删除发现的),主节点会生成一条 DEL 命令,并将其同步给所有的从节点,从节点执行这条 DEL 命令来删除对应的过期键,从而保证主从数据的一致性。

5. 过期删除 vs 内存淘汰

过期删除解决的是“键到了 TTL 要消失”;内存淘汰(eviction)解决的是“内存不够了要挪位置”。两者经常被混为一谈,但触发条件与后果完全不同。

  • 过期删除:只会删除已经过期的键,触发点是“访问发现过期”或“后台扫描发现过期”。
  • 内存淘汰:当达到 maxmemory 限制时触发,可能会删掉未过期的键,具体由 maxmemory-policy 决定。

常见淘汰策略(记住语义即可):

  • noeviction:不淘汰,写入直接报错。
  • allkeys-lru / allkeys-lfu:从所有键里按 LRU/LFU 淘汰。
  • volatile-lru / volatile-lfu / volatile-ttl:只在带过期时间的键里淘汰。
  • allkeys-random / volatile-random:随机淘汰。

6. 工程化关注点与调优方向

  • 大量键同一时刻过期会造成抖动:缓存 TTL 尽量加随机偏移,避免“雪崩式同时过期”。
  • 大 key 过期删除可能阻塞主线程:对超大对象要评估删除代价,必要时用 UNLINK 做异步释放,或拆分 key 降低单次释放成本。
  • 观察指标闭环:关注 expired_keysevicted_keys、内存占用与延迟(慢命令、事件循环延迟),根据业务 SLO 决定过期强度与淘汰策略。