Redis中删除策略的几种实现方式

2025-11-13 17:50

本文主要是介绍Redis中删除策略的几种实现方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Redis中删除策略的几种实现方式》本文详细介绍了Redis的过期键删除策略和内存淘汰策略,过期键删除策略包括定时删除、惰性删除和定期删除,具有一定的参考价值,感兴趣的可以了解一下...

前言

要全面、深入理解 Redis 的删除策略,需从设计背景核心分类(过期键删除策略 + 内存淘汰策略)内部实现细节与持久化的关联实践选择五个维度展开。Redis 的删除策略本质是为了解决 “内存有限” 与 “性能优先” 的核心矛盾 —— 既要避免内存溢出,又要减少删除操作对单线程主线程的阻塞,同时保证数据一致性。

一、设计背景:为什么需要删除策略?

Redis 是内存数据库,内存资源昂贵且有限,若不主动管理内存,会导致内存溢出(OOM);同时,Redis 支持为键设置过期时间(TjsTL),需保证过期键能被合理清理;此外,Redis 是单线程模型,删除操作若过于耗时,会阻塞主线程,导致响应延迟。因此,Redis 设计了两类互补的删除策略:

  1. 过期键删除策略:主动处理 “已过期但未删除” 的键,减少无效内存占用;
  2. 内存淘汰策略:当内存达到上限时,被动删除部分键以释放内存,保证服务可用性。

二、第一类:过期键的 3 种核心删除策略

Redis 通过过期字典(expires dict) 单独存储所有键的过期时间(key 为目标键,value 为过期时间戳),所有过期键删除策略均基于此字典实现。三种策略各有优劣,Redis 最终采用 “惰性删除 + 定期删除” 的组合方案。

Redis中删除策略的几种实现方式

1. 定时删除(Timed Delete):“实时清理,CPU 杀手”

定义:为每个设置了过期时间的键,创建一个定时器(Timer),当键的过期时间到达时,定时器立即触发,执行DEL命令删除该键。

实现逻辑:

  • 当调用EXPIRE key ttl时,Redis 不仅在过期字典中记录过期时间,还会注册一个定时器;
  • 定时器到期后,直接在主线程中执行删除操作。

优缺点:

优点缺点
内存最 “干净”:过期键立即删除,无无效内存占用;CPU 压力大:若存在大量过期键,定时器密集触发,会占用大量 CPU 资源,导致主线程阻塞,影响 Redis 响应速度;
数据一致性高:不会出现 “读取到过期键” 的情况;定时器管理成本高:每个过期键对应一个定时器,内存开销也会增加。

适用场景:

几乎不适用。Redis 是单线程模型,定时删除的 CPU 开销会严重影响服务性能,因此 Redis未采用此策略。

2. 惰性删除(Lazy Delete):“用的时候再删,内存隐患”

定义:Redis 不主动删除过期键,而是在访问键的瞬间(如GETHGETSETNX等操作),才检查该键是否过期:

  • 若未过期:正常返回键值;
  • 若已过期:执行DEL命令删除该键,返回nil(空)。

实现逻辑:

GET key为例:

  1. 先检查key是否存在于过期字典中;
  2. 若不存在:直接返回键值;
  3. 若存在:对比当前时间与过期时间戳,判断是否过期;
  4. 若已过期:删除key(从数据库字典和过期字典中同时移除),返回niphpl
  5. 若未过期:返回键值。

优缺点:

优点缺点
CPU 友好:仅在 “访问过期键” 时才执行删除,无额外 CPU 开销,不影响主线程正常请求;内存泄漏风险:若大量过期键长期不被访问,会一直占用内存(“僵尸键”),导致内存利用率低,甚至触发内存上限;
实现简单:无需管理定时器,逻辑轻量;可能出现 “瞬时过期键”:若过期键未被访问,其他操作(如KEYSDBSIZE)会统计到这些过期键,导致数据统计不准确。

3. 定期删除(Periodic Delete):“折中方案,平衡 CPU 与内存”

定义:   Redis 每隔一段时间(默认 100ms),主动扫描部分过期键并删除,扫描频率和范围由配置控制,避免一次性扫描所有过期键导致阻塞。

核心实现逻辑(Redis 6.0+)

  1. 扫描频率:由hz配置控制(默认hz 10,即每秒执行 10 次定期扫描,每次间隔约 100ms);
  2. 扫描范围:每次扫描不遍历所有过期键,而是采用 “采样 + 限制时间” 的方式:
    • 从过期字典中随机抽取N个键(默认N=20);
    • 检查这些键是否过期,删除已过期的键;
    • 若删除的键占比超过25%(即删除数≥5),则继续抽取N个键重复扫描;
    • 若占比≤25%,或扫描时间超过2ms(避免阻塞主线程),则停止本次扫描。

优缺点:

优点缺点
平衡 CPU 与内存:既避免了定时删除的 CPU 压力,也缓解了惰性删除的内存泄漏问题;扫描参数难调优:hzN25%阈值需根据业务调整,若hz过高或N过大,会增加 CPU 负担;若过低,则内存清理不及时;
非阻塞设计:单次扫描时间限制在2ms内,不影响主线程处理请求;仍有 “漏删” 可能:部分过期键可能在两次扫描间隔内未被访问,也未被扫描到,暂时占用内存。

4. Redis 的最终选择:惰性删除 + 定期删除

两种策略互补,覆盖大部分场景:

  • 定期删除:主动 “批量清理” 过期键,减少 “僵尸键” 数量,缓解内存压力;
  • 惰性删除:兜底清理 “漏网之鱼”,确保访问时不会返回过期键,保证数据有效性。

例如:一个过期键未被定期扫描删除,但用户访问时,惰性删除会立即清理它;反之,若过期键长期不被访问,定期扫描会逐步清理它。

三、第二类:内存淘汰策略(Maxmemory Eviction)

即使有过期键删除策略,Redis 仍可能因 “大量未设置过期时间的键” 或 “过期键删除不及时” 导致内存达到上限(maxmemory配置)。此时,Redis 会触发内存淘汰策略,删除部分键以释放内存,避免 OOM。

1. 核心前提:maxmemory配置

  • 默认值:0(即不限制内存,仅受系统内存限制,生产环境必须手动设置,如maxmemory 4gb);
  • 触发时机:当 Redis 使用的内存(包括键值对、过期字典、缓冲区等)达到maxmemory时,触发淘汰策略(仅对 “写操作” 触发,读操作不受影响)。

2. 8 种内存淘汰策略(Redis 5.0+)

根据 “淘汰范围” 和 “淘汰算法”,分为 4 类,核心区别是 “是否只淘汰过期键” 和 “用什么规则淘汰”:

策略常量淘汰范围淘汰算法适用场景
noeviction(默认)无(不淘汰任何键)-禁止淘汰,内存满时拒绝所有写请求(返回OOM command not allowed),适合不允许数据丢失的场景(如核心配置存储)。
volatile-lru仅淘汰 &ldquohttp://www.chinasem.cn;设置了过期时间” 的键LRU(最近最少使用)希望保留常用的过期键,淘汰不常用的,适合有明确过期时间且需优先保留热点数据的场景(如缓存用户会话)。
allkeys-lru所有键(无论是否过期)LRU(最近最少使用)不清楚哪些键常用,希望淘汰长期未访问的键,适合通用缓存场景(如商品详情缓存)。
volatile-lfu仅淘汰 “设置了过期时间” 的键LFU(最不经常使用)比 LRU 更精准(统计 “访问频率” 而非 “最近访问时间”),适合淘汰低频访问的过期键(如低频访问的活动页面缓存)。
allkeys-lfu所有键(无论是否过期)LFU(最不经常使用)适合需要精准淘汰 “低频率访问” 键的场景(如内容推荐系统,淘汰很少被点击的内容)。
volatile-random仅淘汰 “设置了过期时间” 的键随机淘汰适合对淘汰键无明确优先级,仅需释放内存的场景(较少用)。
allkeys-random所有键(无论是否过期)随机淘汰适合数据无热点、淘汰任意键均可的场景(极少用)。
volatile-ttl仅淘汰 “设置了过期时间” 的键淘汰 “剩余 TTL 最短” 的键希望尽快删除快过期的键,释放内存给新键,适合需优先保留 “剩余时间长” 的过期键的场景(如短期活动缓存,优先保留刚创建的活动数据)。

maxmemory最大可使用内存 占用物理内存的比例,默认值为0,表示不限制,生产环境中根据需求设定,通常设置在50%以上。

maxmemory-samples每次选取待删除数据的个数 选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。因此采用随机获取数据的方式 作为待检测删除数据

maxmemory-policy删除策略

检测易失数据(可能会过期的数据集server.db[i].expires )

① volatile-lru:挑选最近最少使用的数据淘汰

② volatile-lfu:挑选最近使用次数最少的数据淘汰

③ volatile-ttl:挑选将要过期的数据淘汰

④ volatile-random:任意选择数据淘汰 检测全库数据(所有数据集server.db[i].dict )

⑤ allkeys-lru:挑选最近最少使用的数据淘汰

⑥ allkeys-lfu:挑选最近使用次数最少的数据淘汰

⑦ allkeys-random:任意选择数据淘汰 放弃数据驱逐

⑧ no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发错误OOM(Out Of Memory)达到最大内存后的,对被挑选出来的数据进行删除的策略,如下图:

Redis中删除策略的几种实现方式

四、实践建议:如何选择删除策略?

  1. 优先关闭默认的noeviction策略:生产环境若用 Redis 做缓存,noeviction会导致内存满时写请求失败,建议替换为allkehttp://www.chinasem.cnys-lru或allkeys-lfu;
  2. 根据业务场景选择淘汰算法:
    • 通用缓存(如商品、页面缓存):选allkeys-lru(简单且有效);
    • 访问频率波动大的场景(如内容推荐、促销活动):选allkeys-lfu(更精准);
    • 有明确过期时间的场景(如会话、短期活动):选volatile-ttl或volatile-lfu;
  3. 合理配置maxmemory和hz:
    • maxmemory:建议设置为物理内存的 50%-70%(避免 Redis 占用过多内存导致系统 OOM);
    • hz:默认 10 即可,若内存压力大,可适当提高到 20(增加定期扫描频率),但不建议超过 100(避免 CPU 开销过高);
  4. 避免大量设置短期过期键:若需频繁清理短期数据,优先用volatile-ttl策略,而非依赖定时删除。

总结

Redis 的删除策略是 “主动清理(定期删除)+ 被动兜底(惰性删除)+ 内存溢出保护(内存淘汰)” 的三层架构,核心目标是平衡 CPU 资源、内存资源与数据一致性。理解每种策略的适用场景,结合业务需求选择合适的内存淘汰策略,是保障 Redis 高性能、高可用的关键。

到此这篇关于Redis中删除策略的几种实现方式的文章就介绍到这了,更多相关Redis 删除策略内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Redis中删除策略的几种实现方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156153

相关文章

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

检查 Nginx 是否启动的几种方法

《检查Nginx是否启动的几种方法》本文主要介绍了检查Nginx是否启动的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1. 使用 systemctl 命令(推荐)2. 使用 service 命令3. 检查进程是否存在4

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

idea设置快捷键风格方式

《idea设置快捷键风格方式》在IntelliJIDEA中设置快捷键风格,打开IDEA,进入设置页面,选择Keymap,从Keymaps下拉列表中选择或复制想要的快捷键风格,点击Apply和OK即可使... 目录idea设www.chinasem.cn置快捷键风格按照以下步骤进行总结idea设置快捷键pyth

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra