Redis过期删除与内存淘汰策略详解

在Redis的使用过程中,过期删除策略内存淘汰策略是两个核心机制,直接关系到Redis的内存使用效率和系统稳定性。今天我们就来详细聊聊这两个话题,一文帮你彻底搞懂!

一、过期删除策略

1. 如何设置过期时间?

Redis提供了多种命令来设置key的过期时间:

命令 说明 示例
EXPIRE key seconds 设置key在seconds秒后过期 EXPIRE name 60(60秒后过期)
PEXPIRE key milliseconds 设置key在milliseconds毫秒后过期 PEXPIRE name 60000(60000毫秒后过期)
EXPIREAT key timestamp 设置key在指定的时间戳(秒)过期 EXPIREAT name 1735689600(2025-01-01 00:00:00过期)
PEXPIREAT key milliseconds-timestamp 设置key在指定的时间戳(毫秒)过期 PEXPIREAT name 1735689600000
SETEX key seconds value 设置字符串key的同时指定过期时间 SETEX name 60 "zhangsan"
PSETEX key milliseconds value 设置字符串key的同时指定毫秒级过期时间 PSETEX name 60000 "zhangsan"

查看剩余过期时间:

  • TTL key:查看key剩余的过期时间(秒)
  • PTTL key:查看key剩余的过期时间(毫秒)

取消过期时间:

  • PERSIST key:移除key的过期时间,使其永不过期

2. 如何判定key已过期?

Redis内部维护了一个名为**expires的字典**(也称为过期字典),专门用来保存设置了过期时间的key及其过期时间。

过期字典的结构:

  • key:指向实际存储的key对象
  • value :一个long long类型的整数,保存了key的过期时间(毫秒级时间戳)

判定逻辑: 当需要判断一个key是否过期时,Redis会:

  1. 在expires字典中查找该key
  2. 如果找到,获取其过期时间
  3. 将过期时间与当前系统时间比较
  4. 如果当前时间 > 过期时间,则判定为过期

3. 过期删除策略有哪些?

在讨论Redis的具体策略之前,我们先了解常见的过期删除策略:

策略 工作原理 优点 缺点
定时删除 设置key过期时间时,创建一个定时器,到期立即删除 内存友好,及时释放空间 CPU不友好,大量key会占用大量CPU资源
惰性删除 每次访问key时检查是否过期,过期则删除 CPU友好,只检查被访问的key 内存不友好,过期key可能长时间占用内存
定期删除 每隔一段时间,随机检查一部分key,删除过期key 折中方案,平衡CPU和内存 难以确定合适的执行频率

4. Redis过期删除策略是什么?

Redis采用的是惰性删除 + 定期删除的组合策略。

(1)惰性删除

当客户端访问一个key时,Redis会先检查该key是否在过期字典中:

  • 如果已过期,删除该key,然后返回nil
  • 如果未过期,正常返回数据

代码逻辑伪代码:

c 复制代码
if (key 已过期) {
    delete key;
    return null;
} else {
    return key.value;
}

优点 :对CPU友好,只检查被访问的key 缺点:如果key过期后一直不被访问,会一直占用内存

(2)定期删除

Redis会每隔一段时间(默认100ms)执行一次过期key清理,具体流程:

  1. 从所有数据库中随机抽取20个设置了过期时间的key
  2. 检查这20个key,删除其中已过期的key
  3. 如果过期key的比例超过25%(即删除了5个以上),则重复步骤1
  4. 否则,本次清理结束,等待下一次清理

配置参数:

  • hz:serverCron任务的执行频率,默认10,即每秒执行10次,每次清理时间约25ms
  • 可以通过CONFIG SET hz 20调整,增大频率会提高清理速度,但会增加CPU负担

定期删除的特点:

  • 不会遍历所有key,而是随机抽样,避免长时间阻塞
  • 自适应:如果过期比例高,会持续清理
  • CPU和内存的平衡:通过参数可调

为什么采用组合策略?

策略 解决的问题 不足之处 互补关系
惰性删除 避免无谓的CPU消耗 过期key可能长期占用内存 定期删除清理这些key
定期删除 主动清理过期key,释放内存 执行频率不好确定 惰性删除作为补充

两者结合:Redis既保证了CPU的高效利用,又避免了过期key长期占用内存,是一种非常精妙的设计。


二、内存淘汰策略

当Redis内存使用达到上限时,就需要通过内存淘汰策略来腾出空间存储新数据。

1. 如何设置Redis最大运行内存?

(1)配置文件方式(redis.conf)

conf 复制代码
# 设置最大内存为2GB
maxmemory 2gb

# 或者设置字节数
maxmemory 2097152000

(2)命令行方式(运行时修改)

bash 复制代码
# 设置最大内存为2GB
CONFIG SET maxmemory 2gb

# 查看当前设置
CONFIG GET maxmemory

(3)不设置maxmemory会怎样?

  • 在64位系统中,maxmemory默认为0,表示不限制内存使用
  • 如果不限制,Redis会一直使用内存直到耗尽系统所有内存,可能导致系统OOM(Out of Memory)
  • 生产环境强烈建议设置maxmemory,并配置合理的淘汰策略

2. Redis内存淘汰策略有哪些?

Redis提供了多种内存淘汰策略,主要分为三大类:

类别 策略 说明 适用场景
不淘汰 noeviction 内存不够时直接返回错误(默认策略 不允许丢失数据的场景
所有key中淘汰 allkeys-random 从所有key中随机挑选淘汰 访问概率均匀的场景
allkeys-lru 淘汰最近最少使用的key 有热点数据的场景
allkeys-lfu 淘汰使用频率最低的key(4.0+) 有明确热点的场景
过期key中淘汰 volatile-random 从设置了过期时间的key中随机挑选淘汰 缓存场景
volatile-lru 淘汰最近最少使用的过期key 缓存场景,有热点
volatile-ttl 淘汰快要过期的key 缓存场景,优先淘汰即将过期的
volatile-lfu 淘汰使用频率最低的过期key(4.0+) 缓存场景,有明确热点

如何设置淘汰策略?

bash 复制代码
# 配置文件设置
maxmemory-policy allkeys-lru

# 命令行设置
CONFIG SET maxmemory-policy allkeys-lru

# 查看当前策略
CONFIG GET maxmemory-policy

各策略的优缺点对比

策略 优点 缺点 推荐指数
noeviction 数据不丢失 写入可能失败 ⭐⭐
allkeys-lru 保留热点数据 实现稍复杂 ⭐⭐⭐⭐⭐
allkeys-lfu 精准识别热点 需要统计频率 ⭐⭐⭐⭐
volatile-ttl 优先淘汰快过期的 需要设置过期时间 ⭐⭐⭐
allkeys-random 实现简单 可能淘汰热点 ⭐⭐

3. LRU算法和LFU算法有什么区别?

LRU(Least Recently Used)最近最少使用

设计原则:如果一个数据近期没有被访问,那么之后一段时间也不会被访问。

实现方式 :记录每个key的最后访问时间,淘汰时选择最久没被访问的key。

示例

css 复制代码
访问顺序:A → B → C → D → B
当前缓存:[D, B, C](假设容量为3)
新访问E时:淘汰A(最久未访问)

Redis中的近似LRU

  • Redis并没有实现标准的LRU(需要维护双向链表,占用额外内存)
  • 而是采用近似LRU:随机抽样,淘汰其中空闲时间最长的
  • 通过maxmemory-samples配置抽样数量(默认5),越大越接近真实LRU
bash 复制代码
# 设置抽样数量
CONFIG SET maxmemory-samples 10

LFU(Least Frequently Used)最不经常使用

设计原则:如果一个数据最近被访问的次数多,那么之后被访问的概率也会越大。

实现方式 :记录每个key的访问频率,淘汰时选择访问频率最低的key。

示例

scss 复制代码
访问统计:A(100次) B(50次) C(30次) D(10次)
当前缓存:[A, B, C]
新访问E时:淘汰D(频率最低)

Redis中的LFU实现

  • 每个key维护一个24bit的计数器
  • 计数器不是简单的累加,而是对数递增,越往后增长越慢
  • 同时计数器会随时间衰减,避免长期热点永不淘汰
  • 通过lfu-decay-timelfu-log-factor调整行为
bash 复制代码
# 设置计数器衰减时间(分钟)
CONFIG SET lfu-decay-time 1

# 设置对数因子,影响计数器增长速度
CONFIG SET lfu-log-factor 10

LRU和LFU的对比

对比维度 LRU算法 LFU算法
淘汰依据 最近访问时间 访问频率
实现复杂度 相对简单 相对复杂
内存占用 需要记录访问时间 需要计数器
热点识别 只能识别近期热点 能识别长期热点
适用场景 访问模式随时间变化 热点相对固定
缺点 突发流量可能污染缓存 计数器需要衰减机制

选型建议

业务场景 推荐策略 原因
电商大促、新闻热点 allkeys-lru 热点随时间变化,LRU更合适
长尾数据、固定热点 allkeys-lfu 某些key长期高访问,LFU更准确
缓存场景(可重建) volatile-* 只淘汰有TTL的key,避免丢失持久数据
数据不能丢 noeviction 严格控制,宁愿失败也不丢数据

总结

过期删除策略 vs 内存淘汰策略

对比项 过期删除策略 内存淘汰策略
触发条件 key到达过期时间 内存达到maxmemory上限
作用对象 设置了TTL的key 所有key(取决于策略)
执行时机 访问时(惰性)、定时(定期) 写入新数据时
核心目的 释放过期key占用的内存 腾出空间存新数据
Redis策略 惰性删除 + 定期删除 8种淘汰策略可选

配置建议

  1. 生产环境一定要设置maxmemory,避免内存溢出
  2. 根据业务特点选择合适的淘汰策略
    • 通用场景:allkeys-lru
    • 明确热点场景:allkeys-lfu
    • 缓存场景:volatile-lru
  3. 调整抽样数量maxmemory-samples)平衡精度和性能
  4. 监控命中率,适时调整策略

监控命令

bash 复制代码
# 查看内存使用情况
INFO memory

# 查看命中率
INFO stats | grep keyspace

# 查看淘汰key数量
INFO stats | grep evicted_keys

本文总结:Redis的过期删除策略(惰性删除+定期删除)和内存淘汰策略(8种策略)共同构成了Redis高效的内存管理机制。理解这两大机制的原理和配置,对于保障Redis稳定运行、提高缓存效率至关重要。希望本文能帮助大家全面掌握Redis的内存管理核心知识!


欢迎点赞、收藏、转发,让更多小伙伴看到!

相关推荐
love530love1 天前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
星辰徐哥1 天前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥1 天前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约1 天前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee1 天前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐1 天前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs1 天前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐1 天前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司1 天前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
码农阿豪1 天前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端