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的内存管理核心知识!


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

相关推荐
嘻哈baby1 小时前
SQL Server 和 Oracle 以及 MySQL 有哪些区别?
后端
武子康2 小时前
大数据-237 离线数仓 - Hive 广告业务实战:ODS→DWD 事件解析、广告明细与转化分析落地
大数据·后端·apache hive
绝无仅有2 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
舒一笑2 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
golang学习记2 小时前
GitLens 十大神技:彻底改变你在 VS Code 中的 Git 工作流
前端·后端·visual studio code
兆子龙3 小时前
WebSocket 入门:是什么、有什么用、脚本能帮你做什么
前端·架构
AAA梅狸猫3 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫3 小时前
Handler基本概念
面试
一鹿高歌3 小时前
🔥内存炸了!背刺我的竟然是Redisson!!
后端