0%

redis过期删除

Redis 过期删除与内存淘汰机制详解(基于 6.0.10 版本)

Redis 允许为键设置过期时间,但如何高效处理过期键、避免内存溢出,是其性能优化的核心问题。不同于简单的定时删除,Redis 采用定期删除 + 惰性删除的混合策略处理过期键,并在内存不足时通过淘汰机制释放空间。本文详细解析这两种机制的原理、配置及实践建议。

过期键的删除策略

Redis 未采用 “每个过期键对应一个定时器” 的定时删除策略(避免 CPU 资源耗尽),而是结合定期删除惰性删除,在内存占用与 CPU 消耗之间取得平衡。

1. 惰性删除(Lazy Eviction)

  • 核心逻辑:键过期后不主动删除,仅在被访问时(如 gethget 等命令)才检查是否过期。若过期,则删除该键并返回空;若未过期,则正常返回值。
  • 优势:无需额外 CPU 资源监控过期键,仅在必要时执行删除,适合低频访问的过期键。
  • 劣势:若过期键长期未被访问,会占用内存(“内存泄漏” 风险),需配合定期删除弥补。

2. 定期删除(Periodic Eviction)

  • 核心逻辑:Redis 每隔一段时间(由hz配置控制,默认每秒 10 次)主动扫描部分过期键并删除,具体步骤:
    1. 从 “过期键字典”(专门存储设置了过期时间的键)中随机抽取 20 个键
    2. 删除这 20 个键中已过期的键。
    3. 若过期键占比超过 25%,重复步骤 1(继续抽取删除),直至占比低于 25% 或达到最大扫描时间(默认 25ms)。
  • 配置参数:
    • hz <num>:控制定期扫描的频率(默认 10,即每秒 10 次)。值越大,扫描越频繁,过期键删除越及时,但 CPU 消耗越高。
  • 优势:主动清理长期未访问的过期键,减少内存浪费。
  • 注意:为避免扫描耗时过长阻塞服务,单次扫描时间被限制在 25ms 内,因此无法保证所有过期键都被及时删除。

3. 主从结构中的过期键处理

在主从复制中,过期键的删除存在特殊逻辑:

  • 主服务器:采用上述 “定期 + 惰性” 策略正常删除过期键,并向从服务器发送 del 命令。
  • 从服务器:即使键已过期,也不主动删除,仅在收到主服务器的 del 命令后才删除。
  • 潜在问题:主从同步存在延迟时,从服务器可能返回已过期的键(主服务器已删除,但 del 命令未同步),导致短暂的数据不一致。

内存淘汰机制(Maxmemory Policy)

当 Redis 内存使用达到 maxmemory 配置的阈值时,会触发内存淘汰机制,主动删除部分键以释放空间。淘汰机制的核心是 “按规则筛选并删除键”,具体规则由 maxmemory-policy 配置。

核心配置

  • maxmemory <size>:设置 Redis 最大可用内存(如 maxmemory 1GB),0 表示不限制(默认,生产环境需显式设置)。
  • maxmemory-policy <policy>:设置内存淘汰策略(默认 noeviction)。

8 种淘汰策略及适用场景

策略名称 淘汰规则 适用场景
volatile-lru 仅从设置了过期时间的键中,淘汰最近最少使用(LRU) 的键。 需保留非过期键(如核心配置),仅淘汰临时过期数据(如缓存)。
allkeys-lru 所有键中,淘汰最近最少使用(LRU) 的键。 所有键均为缓存数据,优先保留频繁访问的键(如热点商品)。
volatile-lfu 仅从设置了过期时间的键中,淘汰最少频率使用(LFU) 的键。 需区分访问频率(如低频访问的临时数据)。
allkeys-lfu 所有键中,淘汰最少频率使用(LFU) 的键。 适合按访问频率区分优先级的场景(如用户行为日志,高频访问保留)。
volatile-random 设置了过期时间的键中,随机淘汰 过期键访问频率均匀,无需区分优先级。
allkeys-random 所有键中,随机淘汰 所有键重要性相近,随机淘汰影响最小(如临时会话数据)。
volatile-ttl 设置了过期时间的键中,淘汰剩余过期时间最短(TTL 最小) 的键。 需优先保留长期有效的过期键(如即将过期的促销活动数据优先淘汰)。
noeviction(默认) 不淘汰任何键,写操作返回错误(读操作正常)。 不允许数据丢失的场景(如核心业务计数器),需手动扩容或清理。

LRU/LFU 算法的实现细节

(1)LRU(Least Recently Used,最近最少使用)
  • 原理:优先淘汰最长时间未被访问的键。
  • Redis 实现:
    • 每个键的 redisObject 结构中包含一个 24bit 的 lru 字段,记录最后一次访问的时间戳
    • 淘汰时采用采样淘汰:随机抽取 maxmemory-samples 个键(默认 5),淘汰其中 lru 时间最早的键。
    • 重复采样淘汰,直至内存低于 maxmemory
(2)LFU(Least Frequently Used,最少频率使用)
  • 原理:优先淘汰访问频率最低的键(6.0 版本新增)。
  • Redis 实现:
    • 每个键的 redisObject 结构中包含一个 24bit 的 lfu 字段,高 16bit 记录最近访问时间,低 8bit 记录访问频率(计数器)
    • 频率计数器随访问递增,但会随时间衰减(避免长期低频键占据高位)。
(3)采样率配置(maxmemory-samples
  • 作用:控制 LRU/LFU 淘汰时的采样数量(默认 5)。
  • 影响:
    • 采样率越高(如 10),选出的 “最该淘汰的键” 越准确,但 CPU 消耗越高。
    • 采样率越低(如 3),CPU 消耗低,但可能淘汰不该淘汰的键。
  • 建议:默认 5 已平衡准确性与性能,无需频繁调整。

配置与实践建议

关键配置示例

1
2
3
4
5
6
7
8
9
10
11
# 设置最大可用内存为 2GB
maxmemory 2GB

# 选择淘汰策略(推荐 allkeys-lru 或 volatile-lru,根据业务场景)
maxmemory-policy allkeys-lru

# 采样率(默认 5)
maxmemory-samples 5

# 定期扫描频率(默认 10,范围 1-500)
hz 10

通过命令动态修改:

1
2
3
4
5
# 设置最大内存为 1GB
127.0.0.1:6379> config set maxmemory 1073741824

# 切换淘汰策略为 volatile-lru
127.0.0.1:6379> config set maxmemory-policy volatile-lru

实践建议

  • 避免大量键同时过期:定期删除时若大量键同时过期,可能导致扫描时间超过 25ms,阻塞服务。建议过期时间随机化(如 expire key 3600 + rand(0, 100))。
  • 优先使用 LRU/LFU 策略:相比随机或 TTL 策略,LRU/LFU 更符合 “保留有用数据” 的需求,适合缓存场景。
  • 主从环境注意内存差异:从服务器可能因未及时删除过期键而占用更多内存,建议从节点内存配置大于主节点。
  • 监控内存使用率:通过 info memory 查看 used_memorymaxmemory,确保内存使用率稳定在 80% 以下,避免频繁触发淘汰

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10