云计算百科
云计算领域专业知识百科平台

Redis过期键删除策略深度解析

Redis过期键删除策略深度解析

在Redis的实际应用中,缓存过期、内存占用过高是开发和运维过程中高频遇到的问题,而过期键删除策略是Redis解决该问题的核心机制。合理的过期键删除策略能在CPU资源占用和内存利用率之间找到最佳平衡,也是Redis高性能的重要保障。本文将从过期键的基础操作、核心删除策略、Redis实际实现、特殊场景处理等方面全面解析。

一、基础铺垫:Redis过期键的设置与管理

要理解过期键删除策略,首先需要掌握Redis中过期键的基本操作,以及Redis底层如何存储过期键信息。

1.1 过期时间的设置与查询

Redis提供了多种命令为key设置过期时间,同时支持查询剩余存活时间、取消过期时间等操作,覆盖秒/毫秒、时间戳等多种维度。

操作类型命令说明示例
设置过期(秒) expire key n 设key在n秒后过期 expire user:1 60
设置过期(毫秒) pexpire key n 设key在n毫秒后过期 pexpire user:1 60000
时间戳过期(秒) expireat key n 设key在秒级时间戳n后过期 expireat user:1 1736179200
时间戳过期(毫秒) pexpireat key n 设key在毫秒级时间戳n后过期 pexpireat user:1 1736179200123
设值同时过期(秒) set key value ex n 原子操作,设值并指定秒级过期 set session 123 ex 60
设值同时过期(秒) setex key n value 专用命令,等价于上述ex操作 setex token 300 abc123
查询剩余时间 ttl key 返回剩余秒数,-1永不过期,-2已过期/不存在 ttl user:1 → (integer)56
取消过期时间 persist key 移除key的过期时间,变为永久有效 persist user:1 → (integer)1

1.2 过期字典:Redis底层的过期键存储

当为key设置过期时间后,Redis会将该key的过期信息存储在过期字典(expires dict) 中,该字典是Redis数据库结构redisDb的核心组成部分。

底层结构定义如下:

typedef struct redisDb{
dict *dict; // 存放数据库所有键值对
dict *expires; // 过期字典,存放key的过期时间
// 其他属性…
}redisDb;

过期字典的核心特征:

  • key:指向Redis中键对象的指针,与dict中的key一一对应;
  • value:long long型整数,存储key的毫秒级Unix时间戳;
  • 时间复杂度:基于哈希表实现,查询、新增、删除的时间复杂度均为O(1)。

Redis判断一个key是否过期的逻辑非常简单:

  • 检查该key是否存在于过期字典中,不存在则永不过期;
  • 若存在,对比当前系统毫秒时间戳与过期字典中的时间戳,当前时间更大则判定为过期。
  • 二、三大核心过期键删除策略

    业界主流的过期键删除策略分为定时删除、惰性删除、定期删除三种,三者的核心差异在于删除时机和资源占用倾向,分别对应“内存优先”、“CPU优先”、“折中平衡”三种设计思路。

    2.1 定时删除:内存友好,CPU不友好

    核心原理

    在为key设置过期时间的同时,创建一个定时事件,当时间到达过期点时,由Redis事件处理器自动执行该key的删除操作。

    执行流程图

    设置key过期时间 → 创建定时事件(绑定过期时间和删除操作)→ 时间到达 → 事件处理器执行删除 → key被清理

    优缺点
    • ✅ 优点:过期key被立即删除,无内存无效占用,对内存利用率最友好;
    • ❌ 缺点:若存在大量过期key,会创建大量定时事件,频繁触发删除操作,占用大量CPU资源,严重影响Redis的核心读写性能。
    适用场景

    几乎无实际适用场景,Redis未采用该策略。

    2.2 惰性删除:CPU友好,内存可能浪费

    核心原理

    Redis不主动检测和删除过期key,只有当客户端访问该key时,才会检查其是否过期;若过期则立即删除,未过期则正常返回键值对。

    执行流程图

    客户端发起key访问请求 → Redis调用expireIfNeeded函数检查过期状态 → 未过期→返回键值对
    ↓ 过期
    删除key(同步/异步)→ 返回null给客户端

    优缺点
    • ✅ 优点:仅在访问时执行检查,几乎不占用额外CPU资源,实现简单,对CPU最友好;
    • ❌ 缺点:若过期key长期不被访问,会一直占用内存,造成内存泄漏风险,极端情况下会导致Redis内存爆满。
    关键实现

    Redis通过核心函数expireIfNeeded实现惰性删除,Redis4.0+支持通过lazyfree_lazy_expire参数配置同步删除或异步删除,避免删除大key时阻塞主线程。

    核心代码片段:

    int expireIfNeeded(redisDb *db, robj *key) {
    mstime_t when = getExpire(db, key);
    mstime_t now = mstime();
    if (when < 0) return 0; // 无过期时间,直接返回
    if (now <= when) return 0; // 未过期,直接返回
    // 主从模式下,从库不主动删除,交给主库处理
    if (server.masterhost != NULL) return 1;
    server.stat_expiredkeys++; // 统计过期删除的key数量
    // 根据配置选择同步/异步删除
    if (server.lazyfree_lazy_expire)
    dbAsyncDelete(db, key); // 异步删除
    else
    dbSyncDelete(db, key); // 同步删除
    notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
    return 1;
    }

    2.3 定期删除:折中方案,平衡CPU与内存

    核心原理

    Redis每隔一段时间,随机从过期字典中抽取一定数量的key进行过期检查,删除其中的过期key;同时通过限制执行时长和频率,避免对CPU造成过度占用。

    执行流程图

    Redis主线程触发定期检查(由serverCron调度)→ 从过期字典随机抽取20个key → 检查并删除过期key
    → 统计过期key占比 → 占比>25%→重复抽样删除 ↓ 占比≤25%/执行时间≥25ms
    结束本轮定期删除

    核心配置与规则

    定期删除的执行逻辑由Redis底层调度器serverCron控制,核心规则和配置如下:

  • 执行频率:默认每秒执行10次,可通过redis.conf中的hz参数修改(取值1~500),hz越高,扫描越频繁,过期key清理越快,但CPU占用越高;
  • 抽样数量:源码写死为20个key,固定不可配置;
  • 循环条件:若本轮抽样的过期key占比超过25%,则继续抽样删除,确保过期key被有效清理;
  • 时间上限:单次定期删除的执行时间不超过25ms,避免循环过度导致Redis主线程卡死。
  • 优缺点
    • ✅ 优点:通过频率、数量、时间三重限制,平衡了CPU占用和内存浪费,是定时删除和惰性删除的折中方案;
    • ❌ 缺点:随机抽样可能导致部分过期key未被检测到,仍会存在一定的内存无效占用;且hz参数需要根据业务场景精细配置,配置不当会影响效果。

    三、Redis的最终选择:惰性删除+定期删除组合策略

    Redis并未选择单一的删除策略,而是采用惰性删除+定期删除的组合策略,充分发挥两者的优点,规避各自的缺点,在合理使用CPU时间和尽量避免内存浪费之间取得最佳平衡。

    3.1 组合策略整体执行流程图

    Redis启动 → 初始化过期字典,维护key过期信息
    ├─ 客户端访问key → 惰性删除:执行expireIfNeeded检查,过期则删除
    └─ 后台定期调度(hz控制频率)→ 定期删除:随机抽样检查,删除过期key
    ↓ 内存占用持续升高 → 触发内存淘汰策略(maxmemory控制)

    3.2 组合策略的核心优势

  • CPU占用可控:惰性删除仅在访问时执行检查,定期删除通过三重限制控制CPU消耗,不会影响Redis核心业务;
  • 内存无效占用可控:定期删除主动清理大部分过期key,惰性删除兜底清理“漏网之鱼”,避免过期key长期堆积;
  • 实现轻量高效:基于过期字典的O(1)查询,搭配简单的抽样和检查逻辑,底层实现无复杂开销。
  • 四、特殊场景:过期键的处理规则

    在Redis的主从模式和持久化(RDB/AOF) 场景下,过期键的处理有特殊规则,这是开发和运维中容易踩坑的点,必须重点掌握。

    4.1 主从模式下的过期键处理

    主从模式中,从库不主动执行过期键删除操作,所有过期键的删除由主库统一控制,保证主从数据一致性:

  • 主库检测到key过期后,执行删除操作,并在AOF文件中追加一条del指令;
  • 主库通过主从同步,将del指令发送给所有从库;
  • 从库执行del指令,完成过期key的删除;
  • 若客户端直接访问从库的过期key,从库会返回原值,直到收到主库的del指令。
  • 4.2 持久化场景下的过期键处理

    过期键在RDB和AOF两种持久化文件中的处理逻辑不同,分为生成/写入阶段和加载/重写阶段。

    RDB文件中的过期键
    • 生成阶段:持久化生成新RDB文件时,Redis会对key进行过期检查,过期key不会被写入RDB文件;
    • 加载阶段:主库加载RDB时,会过滤过期key;从库加载RDB时,会载入所有key(包括过期key),但主从同步后会被清理。
    AOF文件中的过期键
    • 写入阶段:过期key未被删除时,AOF文件会保留其相关记录;当过期key被删除后,Redis会向AOF文件追加del指令,标记该key的删除;
    • 重写阶段:执行AOF重写时,Redis会检查内存中的键值对,过期key不会被写入重写后的AOF文件。

    五、延伸:过期删除策略与内存淘汰策略的配合

    当Redis的运行内存达到maxmemory设置的上限时,仅靠过期删除策略无法解决内存问题,此时会触发内存淘汰策略,删除符合条件的key以释放内存。过期删除策略处理已过期的key,而内存淘汰策略处理内存超限后的key,两者配合构成Redis的完整内存管理体系。

    5.1 内存淘汰策略的分类(Redis4.0+共8种)

    Redis的内存淘汰策略分为三大类,可通过maxmemory-policy参数配置:

  • 不淘汰:noeviction(Redis3.0后默认),内存超限时拒绝所有写操作,仅允许读/删除;
  • 仅淘汰带过期时间的key:volatile-lru/volatile-lfu/volatile-random/volatile-ttl;
  • 淘汰所有key:allkeys-lru(推荐通用场景)/allkeys-lfu/allkeys-random。
  • 5.2 核心推荐配置

    • 通用业务场景:allkeys-lru,淘汰所有key中最近最少使用的,适配绝大多数缓存场景;
    • 热点数据明显场景:allkeys-lfu,淘汰访问频率最低的key,更贴合热点数据分布;
    • 数据不可丢失场景:noeviction,拒绝写操作,避免数据丢失;
    • 部分数据持久化场景:volatile-lru,仅淘汰带过期时间的缓存key,保护持久化数据。

    5.3 实战配置命令

    # 临时设置最大内存为512MB
    CONFIG SET maxmemory 536870912
    # 临时设置内存淘汰策略为allkeys-lru
    CONFIG SET maxmemory-policy allkeys-lru
    # 持久化配置(写入redis.conf)
    CONFIG REWRITE

    六、实战配置与性能优化建议

    结合过期键删除策略的原理,给出以下实战配置和性能优化建议,适配大多数生产环境:

  • 合理设置hz参数:默认hz=10,若Redis内存压力大、过期key多,可适当提高至20~50,加快定期删除频率;若CPU资源紧张,保持默认即可;
  • 开启异步删除:Redis4.0+设置lazyfree_lazy_expire yes,避免删除大key时阻塞主线程;
  • 精准设置过期时间:根据业务场景为key设置合理的TTL,避免无意义的长期缓存,减少过期字典的体积;
  • 配置合理的maxmemory:根据服务器内存大小,设置Redis最大运行内存(建议预留30%以上内存给系统),避免内存爆满;
  • 主从分离:将读请求分散到从库,主库专注于写操作和过期键管理,提升整体性能;
  • 监控过期key指标:通过info stats查看expired_keys指标,监控过期key的删除数量,及时调整策略配置。
  • 七、总结

    Redis的过期键删除策略是其内存管理的核心,核心要点可总结为以下3点:

  • 底层基础:通过过期字典实现过期key的O(1)查询,是所有删除策略的基础;
  • 核心策略:采用惰性删除+定期删除组合策略,平衡CPU资源占用和内存利用率,是Redis高性能的重要保障;
  • 场景适配:主从模式和持久化场景下有特殊的过期键处理规则,内存淘汰策略与过期删除策略配合,构成完整的内存管理体系。
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » Redis过期键删除策略深度解析
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!