Redis 过期键删除和内存淘汰策略【Redis 系列之四】
〇、前言
对于 Redis 服务器来说,内存资源非常宝贵,如果一些过期键一直不被删除,就会造成资源浪费。
那么,本文将结合博主收集的资料,简单介绍下过期键删除、内存淘汰两个策略,仅供参考。
博主 Redis 相关文章都在这里了:https://www.cnblogs.com/hnzhengfy/category/2229717.html
一、Redis 的过期时间配置
1.1 设置过期时间的方法
首先是在设置键值对的同时指定过期时间:
# 语法
SET key value [EX seconds] [PX milliseconds]
# 示例
SET mykey "hello" EX 60 # 设置 mykey 的值为 "hello",并在 60 秒后过期
SET mykey "hello" PX 60000 # 设置 mykey 的值为 "hello",并在 60000 毫秒(即 60 秒)后过期
然后是给已存在的键添加过期时间,共四种命令:
# 【expire 命令】设置以【秒】为单位的过期时间
# 语法:
EXPIRE key seconds
# 示例:
SET mykey "hello"
EXPIRE mykey 60 # 设置 mykey 在 60 秒后过期
# 【pexpire 命令】设置以【毫秒】为单位的过期时间
# 语法:
PEXPIRE key milliseconds
# 示例:
SET mykey "hello"
PEXPIRE mykey 60000 # 设置 mykey 在 60000 毫秒(即 60 秒)后过期
# 【expireat 命令】设置一个具体的 Unix 时间戳作为过期时间(以【秒】为单位)
# 语法:
EXPIREAT key timestamp
# 示例:
SET mykey "hello"
EXPIREAT mykey 1743283200 # 设置 mykey 在 Unix 时间戳 1743283200 时过期
# 【pexpireat 命令】设置一个具体的 Unix 时间戳作为过期时间(以【毫秒】为单位)
# 语法:
PEXPIREAT key timestamp_ms
# 示例:
SET mykey "hello"
PEXPIREAT mykey 1743283200000 # 设置 mykey 在 Unix 时间戳 1743283200000 时过期
1.2 如何判断一个键是否已经过期?
- 首先看下一个带过期时间的键如何保存?
Redis 在内存中存储键值对时,会为每个键维护一个独立的数据结构来记录其元信息(如过期时间)。
键值对存储在全局哈希表(dict)中。每个键对应一个 redisObject,该对象包含了键的值以及与该键相关的元信息(例如类型、编码方式等)。
过期时间存储在一个专门的字典(expires 字典)中,键是普通键名,值是该键的过期时间(以 Unix 时间戳的形式存储)。
# 示例
SET mykey "hello" EX 60
# mykey 被存储在主字典中,指向值 "hello"。
# 同时,mykey 也会被添加到 expires 字典中,值为当前时间 + 60 秒的时间戳。
如果一个键没有设置过期时间,则它不会出现在 expires 字典中。
- 读取键时会先进行过期检查
当访问一个键时(如 GET 命令),Redis 会先检查该键是否存在于 expires 字典中。如果存在,Redis 会将当前时间与 expires 字典中存储的过期时间进行比较:
如果,当前时间 >= 过期时间:认为该键已过期,返回 nil。
如果,当前时间 < 过期时间:认为该键仍然有效。
二、过期键删除策略
2.1 惰性删除(Lazy Deletion)(被动删除)
惰性删除是 Redis 核心工作机制的一部分,因此默认启用,并且无法通过配置项来手动关闭。
针对惰性删除有三个要点:
被动触发:当客户端访问一个键时(如 GET、DEL 等命令),Redis 会首先检查该键是否已设置过期时间。
过期检查:如果键已过期(当前时间 ≥ 过期时间),Redis 会立即删除该键,并返回 nil(表示键不存在)。
不主动清理:未被访问的过期键不会被删除,直到下次被访问时才会触发检查。
- 优势
高效性:仅在键被访问时检查过期,避免了不必要的 CPU 资源消耗。
低延迟:不会因过期键的清理操作导致系统性能波动。
- 劣势
内存浪费:长时间未被访问的过期键会持续占用内存,可能导致内存泄漏。
不可控性:无法主动清理未被访问的过期键。
2.2 定期删除(Periodic Deletion)(主动删除)
定期删除就是以固定的时间间隔,来扫描 Redis 数据库中的键,发现过期的键立即删掉,可以通过配置来设置具体频率。
要点:
主动触发:Redis 内部通过一个后台任务(serverCron)周期性地扫描过期键,并主动删除它们。
随机采样:每次扫描时,Redis 会从数据库的 expires 字典中随机选取一批键(默认 20 个),检查是否过期,并删除已过期的键。
动态调整:通过参数 hz(默认值 10)控制扫描频率,即每秒执行 hz 次扫描任务。扫描时长受 CPU 时间限制(默认不超过 25% 的 CPU 时间)。
简要的步骤:
- 遍历所有数据库:依次检查每个数据库(DB)。
- 随机采样:从每个数据库的 expires 字典中随机选取 20 个键。
- 删除过期键:将过期的键从主字典和 expires 字典中删除。
- 重复扫描:如果发现 25% 以上的采样键已过期,则重复扫描,直到过期键比例低于阈值或达到 CPU 时间限制。
- 退出条件:若达到预设的 CPU 时间限制(如每秒 25ms),则停止扫描。
- 优势:
内存友好:主动清理过期键,减少内存浪费。
可控性:通过调整 hz 和扫描参数,平衡性能与内存占用。
- 劣势:
延迟性:过期键可能在扫描间隔内仍存在,无法立即删除。
资源占用:频繁扫描可能增加 CPU 负载(但通过时间限制避免了极端情况)。
- 如何配置?
hz:配置 serverCron 的执行频率(默认 10,即每秒 10 次)。
ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC:该参数决定了 Redis 在单次过期键清理周期中,最多可以占用的 CPU 时间比例(默认 25%)。
# 计算公式:
最大允许 CPU 时间(微秒) = (1000000 * ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC) / (server.hz * 100)
# 例如:当 hz=10
最大允许时间 = (1000000 * 25) / (10 * 100) = 25,000 微秒(即 25 毫秒) # 单次清理,只运行 25 毫秒
# 例如:当 hz=1
最大允许时间 = (1000000 * 25) / (1 * 100) = 250,000 微秒(即 250 毫秒) # 单次清理,只运行 250 毫秒
若某次清理发现大量过期键(如 20 个采样键中有 6 个过期),Redis 会继续扫描直到过期键比例下降或时间耗尽。
2.3 综合策略:惰性删除+定期删除
Redis 的过期键删除策略结合了惰性删除(Lazy Deletion)和定期删除(Periodic Deletion),通过两者的互补性实现性能与内存占用的平衡。
两者结合带来的好处:
高效性:惰性删除仅在键被访问时触发,避免了不必要的 CPU 开销。定期删除通过随机采样和动态调整,平衡了 CPU 负载与内存清理效率。
内存友好:惰性删除确保被访问的过期键立即释放内存。定期删除主动清理未被访问的过期键,减少内存泄漏风险。
典型应用场景:
针对高频访问场景,惰性删除更有优势,能够快速清理过期键,减少内存占用。当然,不可避免的有部分键是没有被访问的,这时就需要定期删除来及时清理。
针对内存敏感场景,定期删除可以避免过期键长期占用空间,但要仔细考量配置项的值,避免 CPU 过载。惰性删除则尽快清除失效键。
针对低资源环境,更加需要两者的有机配合。惰性删除减少 CPU 开销,定期删除通过参数控制资源消耗。也可能需牺牲部分内存利用率以换取 CPU 节省。
三、内存淘汰策略
3.1 触发条件
Redis 的内存淘汰策略(Memory Eviction Policy)是在 Redis 达到最大内存限制(由 maxmemory 参数配置)时,用于决定如何淘汰(删除)现有数据以腾出空间的机制。
两个条件全部满足才触发:
- 达到最大内存限制:当 Redis 使用的内存超过 maxmemory 配置的阈值时。
- 需要分配新内存:当尝试写入新数据或更新现有数据时,如果内存不足,触发淘汰策略。
3.2 八种内存淘汰策略
八种策略实际上可以分为三类。
1)不淘汰任何数据(默认策略)
- maxmemory-policy noeviction
当内存不足时,拒绝所有写操作(如SET、ADD等),并返回错误(OOM command not allowed when used memory > 'maxmemory')。
适用于对数据完整性要求高的场景,避免因内存不足导致数据丢失。
2)在所有键(allkeys)中选择淘汰
这类策略会从所有键(无论是否设置了过期时间)中选择淘汰对象。
- maxmemory-policy allkeys-lru
淘汰最近最少使用的(Least Recently Used)键。根据键的最近访问时间(上次读或写的时间),选择最久未使用的键淘汰。
适合访问模式不固定、需要保留近期活跃数据的场景。
- maxmemory-policy allkeys-lfu
淘汰最近最少使用的(Least Frequently Used)键。根据键的访问频率(读写次数),选择使用频率最低的键淘汰。
适合频繁访问少数热点数据的场景(如热门商品缓存)。
- maxmemory-policy allkeys-random
随机选择一个键淘汰。
适用于对数据淘汰的公平性要求不高,追求简单快速的淘汰方式。
3)仅在设置了过期时间的键(volatile)中选择淘汰
这类策略仅从设置了过期时间的键中选择淘汰对象。
- maxmemory-policy volatile-lru
在设置了过期时间的键中,淘汰最近最少使用的(Least Recently Used)键。
适用于需要淘汰过期可能性高的键,同时保留近期活跃数据。
- maxmemory-policy volatile-lfu
在设置了过期时间的键中,淘汰最近最少使用的(Least Frequently Used)键。
适合访问频率低但即将过期的键。
- maxmemory-policy volatile-random
在设置了过期时间的键中随机选择一个淘汰。
适用于对过期键的淘汰公平性要求不高的场景。
- maxmemory-policy volatile-ttl
优先淘汰剩余生存时间(TTL:Time To Live)最短的键。如果多个键的 TTL 相近,则可能随机选择。
适用于希望尽快清理即将过期的键,避免内存浪费的场景。
注意:volatile-ttl 策略可能因时间因素导致某些键被提前淘汰,即使它们仍被频繁访问。
| 业务场景 | 推荐使用的策略 |
| 数据完整性要求高 | 使用 noeviction,避免写入失败 |
| 访问模式不固定 | 使用 allkeys-lru 或 volatile-lru |
| 存在热点数据 | 使用 allkeys-lfu 或 volatile-lfu |
| 希望优先清理即将过期的数据 | 使用 volatile-ttl |
| 简单快速淘汰 | 使用 allkeys-random 或 volatile-random |
注意:Redis 的 LRU 和 LFU 并非精确实现,而是通过采样和统计来近似计算,以减少性能开销。例如,maxmemory-policy allkeys-lru 会定期采样部分键来估算最近最少使用情况。
另外,Redis 的内存淘汰策略与键的过期机制(惰性删除+定期删除)是独立的。即使设置了过期时间,未被访问的键仍可能因内存不足被提前淘汰。
3.3 配置和查看
# 配置格式
maxmemory <bytes> # 设置最大内存限制(如:maxmemory 1gb)
maxmemory-policy <policy> # 设置淘汰策略(如:maxmemory-policy allkeys-lru)
# 动态配置(需重启后生效)
CONFIG SET maxmemory 1gb
CONFIG SET maxmemory-policy allkeys-lru
# 查看当前配置项
CONFIG GET maxmemory
CONFIG GET maxmemory-policy
Redis 的内存淘汰策略提供了灵活的选择,需根据业务需求权衡数据保留策略、性能开销和公平性。合理配置 maxmemory 和 maxmemory-policy 是优化 Redis 性能和可靠性的关键。
Redis 过期键删除和内存淘汰策略【Redis 系列之四】的更多相关文章
- 一文了解:Redis过期键删除策略
Redis过期键删除策略 Redis中所有的键都可以设置过期策略,就像是所有的键都可以上"生死簿",上了生死簿的键到时间后阎王就会叉掉这个键.同一时间大量的键过期,阎王就会忙不过来 ...
- Redis 过期键删除策略
Redis 中数据库键的过期时间都保存在过期字典中,当一个键过期了,Redis 存在三种不同的删除策略:定时删除.惰性删除和定期删除 定时删除 定义 在设置键的过期时间的同时创建一个计时器,让定时器在 ...
- redis过期键删除策略以及大key删除方法
今天遇到了一个前同事挖的坑,刷新缓存中商品信息时先让key过期,然后从数据库里取最新数据然后再放到缓存中,他是这样写的 redisTemplate.expire(CacheConst.GOOGS_PR ...
- redis键的过期和内存淘汰策略
键的过期时间 设置过期时间 Redis可以为存储在数据库中的值设置过期时间,作为一个缓存数据库,这个特性是很有帮助的.我们项目中的token或其他登录信息,尤其是短信验证码都是有时间限制的. 按照传统 ...
- 面试官:Redis 过期删除策略和内存淘汰策略有什么区别?
作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林. Redis 的「内存淘汰策略」和「过期删除策略」,很多小伙伴容易混淆,这两个机制虽然都 ...
- redis中key的过期键删除策略
Redis过期键删除策略 Redis key过期的方式有三种: 被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key 主动删除:由于惰性删除策略无法保证冷数据被及时删 ...
- Redis的过期策略和内存淘汰策略(转)
Redis的过期策略 我们都知道,Redis是key-value数据库,我们可以设置Redis中缓存的key的过期时间.Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理. ...
- LRU工程实现源码(一):Redis 内存淘汰策略
目录 内存淘汰是什么?什么时候内存淘汰 内存淘汰策略 Redis中的LRU淘汰算法 源码剖析 第一步:什么时候开始淘汰key 配置读取 检查时机 getMaxmemoryState 第二步:淘汰哪些k ...
- Redis系列11:内存淘汰策略
Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...
- Redis内存淘汰策略
目录 一.内存淘汰策略重要性 二.Key值过期策略 三.内存淘汰策略 三.Redis内存淘汰策略配置 一.内存淘汰策略重要性 我们都知道redis的性能很高,最主要的原因之一就是redis的数据都在内 ...
随机推荐
- Solution -「NOI 2017」「洛谷 P3825」游戏
\(\mathscr{Description}\) Link. 给大家看个乐子: link, 懒得概括题意啦. \(\mathscr{Solution}\) 对于没有 X 的情况, 显然可 ...
- Redis五种数据结构及真实应用场景
前言 如果问你redis有哪些数据结构,你肯定可以一口气说出五种基本数据结构: String(字符串).Hash(哈希).List(列表).Set(集合).zset(有序集合) 你或许还知道它还有三种 ...
- 在linux系统通过OpenSSL工具自签https证书
工具介绍 OpenSSL是SSL/TLS协议的实现工具 key是私钥文件,用于对发送给客户端的数据加密,以及对从客户端接收的数据进行解密. csr是证书签名请求文件,用于提交给证书颁发机构(CA)对证 ...
- Codeforces Round 998 (Div. 3)
题目链接:Codeforces Round 998 (Div. 3) 总结:复建,Cwa两发,E读假题了. A. Fibonacciness tag:签到 Solution:简单模拟一下即可. voi ...
- 一个简易socket通信结构
服务端 基本的结构 工作需要又需要用到socketTCP通讯,这么多年了,终于稍微能写点了.让我说其实也说不出个啥来,看了很多的异步后稍微对异步socket的导流 endreceive后 再begin ...
- 聊聊GRPO算法——从Open R1来看如何训练DeepSeek R1模型
概述 首发自个人公众号:阿郎小哥的随笔驿站 DeepSeek R1系列建议阅读之前的系列文章: 聊聊DeepSeek R1的一些总结 聊聊DeepSeek R1的开源复现库--Open R1之合成数据 ...
- [开源自荐] Catime 不一样的计时器(番茄时钟),非常欢迎反馈
Catime 一款简洁的 Windows 倒计时工具,具有透明界面和丰富的自定义选项. Github:https://github.com/vladelaina/Catime 特点 极简设计: 透明界 ...
- js提示Cannot read property ‘replace‘ of undefined
JS提示Cannot read property 'replace' of undefined 出现这个错误的原因一般是传的参数为null 在传参之前加个是否为null的判断可以解决异常.
- 特征转换之python代码
一.连续型变量1.1 连续变量无量纲化(1)无量纲化: 使不同规格尺度的数据转化统一规格尺度(将数据单位统一)(2)无量纲化方法:标准化, 区间所方法 标准化: 将连续性变量转变为 均值0 标准差1 ...
- error setting certificate verify locations: CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt CApath: none
这个问题是因为git配置里crt证书的路径不正确导致的. 这个路径配置是在C:\Program Files\Git\etc\gitconfig中,应该所有人的配置都在这里 [diff "as ...