Redis键过期策略深度剖析:惰性删除与定期删除的完美平衡
在Redis中,key过期后并不会立即被删除。因为Redis采用了一种结合惰性删除和定期删除的混合策略来清理过期的key,这是为了在内存占用和CPU消耗之间取得平衡。
1. 过期键的删除策略
Redis 并非采用实时删除策略,而是通过以下两种方式协同工作来清理过期键。
1.1 惰性删除
这是一种被动删除策略,其核心原则是:只有在访问一个键时,才去检查并删除它
- 触发时机:当任何命令尝试访问一个键时(如Get ,HGET,EXISTS等),Redis 会首先检查该键是否设置了过期时间以及是否已过期
- 执行流程:
- 接收客户端对键mykey的访问请求
- 检查mykey是否设置了TTL且当前时间>过期时间戳
- 如果已过期,则立即删除该键,并模拟该键不存在的行为
- 如果未过期或者未设置TTL,则正常执行命令
- 优点:对CPU优化,因为删除操作只发生在实际被访问的键上,不会永远不会被访问的过期键消耗计算资源
- 缺点:对内存不友好。如果一个键过期后一致无人访问,它将永远占据内存控件,导致内存泄漏,直到被后续的某种机制删除
1.2 定期删除
这是一种主动删除策略 ,旨在弥补惰性删除的不足。Redis会定期地随机测试和删除一部分过期Key
- 触发时机:由Redis的hz配置参数控制的后台任务周期性执行。默认情况下,Redis每秒执行10次(hz 10)
- 执行流程(每次定期删除循环)
- 随机采样:从设置了过期的时间的键的集合中,随机抽取一定数量的键(由ACTIVE_EXPIRE_CYCLE_LOOKUPS_FER_LOOP定义,通常为20)
- 检查并删除:检查所有被抽中的键,并立即删除其中已过期的键
- 循环事件:如果在本轮采样中,发现超过25%的键已过期,则Redis会认为当前内存中存在大量的过期键,并立即重复步骤1,再次进行采样和删除,直到过期键的比例低于25%或超出时间限制,以防止循环过度占用CPU。
- 优点:通过周期性扫描,减少了因大量过期键无人访问而造成的内存浪费
- 缺点:需要精细调整采样频率和数量。如果设置过于激进,会占用过多CPU,影响正常请求的响应
2. 内存不足时的后被策略:内存淘汰
当Redis实例使用的内存超过maxmemory限制时,会触发内存淘汰限制。这是确保Redis不会因为内存耗尽而崩溃的最后防线。
- 触发条件:used_memory>maxmemory
- 策略配置:通过maxmory-policy参数指定,常见的策略包括:
volatile-lru/allkeys-lru:使用 LRU 算法淘汰设置了 TTL 的键 / 所有键。volatile-ttl:优先淘汰 TTL 较小的键。volatile-random/allkeys-random:随机淘汰。noeviction(默认):不淘汰,拒绝所有会增加内存使用的写入命令。
- 重点:内存淘汰时独立于过期删除的机制。即使一个键尚未过期, 也可能因为内存不足而被淘汰。
3. 对持久化和复制的影响
3.1 RDB持久化
- 创建RDB快照时:已过期的键不会被写入到RDB文件中
- 从RDB文件恢复时:
- 如果Redis以主节点模式运行,它会加载所有数据,并在加载过程中检查过期键
- 如果Redis以从节点模式运行,它会加载所有数据,无论是否过期。因为过期决策应用主节点统一管理,从节点通过主节点的DEL命令同步来删除键
3.2 AOF 持久化
- AOF 文件写入:当一个键因过期被惰性删除或定期删除后,Redis会向AOF文件末追加一条DEL命令,以记录该删除操作
- AOF重写:在重写过程中,类似于RDB,已过期的键不会被写入到新的AOF文件中
3.3 复制模式
在主从复制架构下,从节点不会主动触发定期删除。删除过期键的责任完全由主节点承担:
- 主节点在删除过一个过期键后,会显示地向所有从节点发送一个DEL命令
- 从节点只有收到主节点的DEL命令后,才会删除该键
- 这种中心化的设计保证了主从数据的一致性
4. 监控与最佳实践
4.1 监控指标
使用INFO命令查看过期键的相关统计信息
redis-cli info stats | grep expired_keys
- expired_keys:自Redis启动依赖,被删除的过期键总数
4.2 最佳实践
- 避免大量键同时过期:例如,如果使用缓存,不要再相同的秒级时间点让大量键过期 。可以为过期时间添加一个随即偏移量,如EXPIRE KEY 3600+rand(0,300),将过期时间打散。
- 理解内存占用:意识到惰性删除可能导致“内存看似已用满,但实际包含大量过期键”的情况。定期删除和内存淘汰时应对这种情况的保障。
- 合理配置maxmemory-policy:根据业务重要性,选择是淘汰volatile键还是allkeys。对于缓存场景,allkeys-lru通常是安全的选择
- 谨慎调整hz参数:除非你明确了大量过期键对业务的影响,并且监控到定期删除不及时,否则不建议轻易调高hz值,因为这会增加Redis的CPU开销。
总结
Redis的键过期处理是一个精心设计的权衡方案,它通过惰性删除保证CPU效率,通过定期删除减少内存浪费。理解这一机制对于正确评估Redis的内存使用情况、配置合理的过期策略以及诊断相关产生问题至关重要。从过期键到被实际回收之间存在一个时间窗口,并据此设计应用程序。
