Redis Key过期删除策略详解

Redis 的 Key 过期数据删除策略是 Redis 内存管理的关键部分,它通过 两种主要策略 相结合的方式清理过期数据:

1. 被动删除(惰性删除 - Lazy Expiration)

工作原理:

  • 当客户端尝试访问某个 Key 时,Redis 会先检查该 Key 是否已过期

  • 如果过期,则立即删除并返回 nil(就像 Key 不存在一样)

  • 如果未过期,则正常返回数据

优点:

  • CPU 友好,只在访问时消耗资源

  • 简单直接,不影响未访问的 Key

缺点:

  • 内存不友好,不访问的过期 Key 会一直占用内存

  • 可能导致内存泄露(如果某些过期 Key 永不被访问)

2. 主动删除(定期删除 - Periodic Expiration)

工作原理 :

Redis 会周期性地(默认每秒 10 次)执行以下操作:

  1. 随机测试:从设置了过期时间的 Key 集合中随机选择 20 个 Key

  2. 检查过期:删除其中所有已过期的 Key

  3. 调整频率:如果超过 25% 的 Key 已过期,则重复步骤 1-2

  4. 限制时间:每次扫描最多持续 25ms,避免阻塞主线程

配置参数(redis.conf):

复制代码
conf

# 每秒执行过期扫描的次数(默认 10)
hz 10

# 每次扫描的 CPU 时间百分比上限(默认 25%)
# 实际上每次扫描最多 25ms(1000ms/hz * 25%)

优点:

  • 减少内存中过期 Key 的堆积

  • 在 CPU 和内存之间取得平衡

缺点:

  • 不是实时的,可能存在过期 Key 未被及时清理

  • 增加了一定的 CPU 开销

3. 内存淘汰策略(Eviction Policies)

当内存达到 maxmemory 限制时,Redis 会根据配置的策略删除数据:

复制代码
conf

# 内存限制(默认不限制)
maxmemory <bytes>

# 淘汰策略
maxmemory-policy <policy>

淘汰策略选项:

策略<policy> 描述 适用场景
noeviction 不淘汰,返回错误 数据绝对不能丢失
allkeys-lru 从所有 Key 中使用 LRU 需要缓存效果
volatile-lru 从带过期时间的 Key 中使用 LRU 混合使用
allkeys-random 随机删除所有 Key 所有 Key 同等重要
volatile-random 随机删除带过期时间的 Key 混合使用
volatile-ttl 删除即将过期的 Key(TTL最小) 优先保留新数据
allkeys-lfu 从所有 Key 中使用 LFU(4.0+) 访问频率重要
volatile-lfu 从带过期时间的 Key 中使用 LFU(4.0+) 混合使用

4. 实际工作流程示例

5. 性能优化建议

  1. 监控过期 Key 数量:

    复制代码
    bash
    
    # 查看过期 Key 相关信息
    redis-cli info stats | grep expired_keys
  2. 合理配置:

    复制代码
    conf
    
    # 根据负载调整 hz 值
    hz 100  # 更高频率(更及时清理,更高CPU)
    hz 1    # 更低频率(更少CPU,可能堆积)
  3. 避免大量 Key 同时过期:

    python 复制代码
    # 不好的做法:同时设置相同过期时间
    for i in range(100000):
        redis.set(f"key:{i}", "data", ex=3600)
    
    # 好的做法:添加随机偏移
    for i in range(100000):
        redis.set(f"key:{i}", "data", ex=3600 + random.randint(0, 300))

6. 特殊情况处理

  1. AOF/RDB 持久化:

    • RDB:生成快照时,过期 Key 不会被保存

    • AOF :Key 过期时,会追加一条 DEL 命令

  2. 主从复制:

    • 主节点删除过期 Key 后,会向从节点发送 DEL 命令

    • 从节点不会主动删除过期 Key,只接受主节点指令

  3. 集群模式:

    • 每个节点独立管理自己的过期 Key

    • 迁移槽位时,过期信息一并迁移

总结

Redis 的过期删除策略是 惰性删除 + 定期删除 的组合拳:

  • 惰性删除:保证访问的正确性

  • 定期删除:减少内存浪费

  • 内存淘汰:防止内存耗尽的最后防线

这种设计在 CPU 使用率、内存效率和实现复杂性之间取得了良好的平衡,使得 Redis 能够高效处理大量带有过期时间的 Key。

相关推荐
Pniubi4 小时前
HashMap的扩容和树化边界
java·开发语言
Mikko74 小时前
用 Java 复刻了高中时在塞班上玩的「熔岩矿车」:纯 Swing、零依赖、没有一张图片,一个 jar 双击就能玩
java·游戏开发·swing
知了学历孙老师4 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
Java爱好狂.4 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试
秋饼5 小时前
LLM API密钥动态轮换实战:Spring Vault + Spring AI + 多Provider路由
java·ai·技术分享·后端开发
福兮说7 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
紧跟先前的步伐8 小时前
Go AI Agent 实战 03|Token、上下文窗口与模型调用成本
java·人工智能·golang
const_qiu8 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
Wang's Blog8 小时前
Java 项目实战: 交友项目 - 个人资料管理的更新接口实现与坑
java·开发语言·交友
Promising_GEO9 小时前
GEE实战02期:从卫星波段开始:利用 Sentinel-2 自己计算 NDVI
java·sentinel·遥感·空间分析