Redis核心理论:数据删除与淘汰策略详解(从原理到实战)

Redis 作为高性能的内存数据库,所有数据都存储在内存中,而内存资源是有限的------这就引出了两个核心问题:过期数据如何删除?内存满了之后新数据如何存储?

这两个问题分别对应 Redis 的「数据删除策略」和「数据淘汰策略」,二者相辅相成,共同决定了 Redis 的性能、内存利用率和数据一致性。很多开发者在使用 Redis 时,容易混淆这两个概念,甚至因配置不当导致内存溢出、数据丢失或性能瓶颈。

本篇博客将从「基础概念铺垫」到「策略细节拆解」,再到「底层原理」和「实战配置」,把 Redis 数据删除与淘汰策略讲透,无论是面试备考还是生产实践,都能直接套用。

一、前置基础:先搞懂2个核心前提

在讲解具体策略前,必须先明确两个基础概念,否则容易理解偏差:

1. 过期数据 vs 非过期数据

Redis 支持给 key 设置过期时间(通过 EXPIRE、PEXPIRE 等命令),过期数据是指「到达预设过期时间但尚未被删除的 key」;非过期数据则是没有设置过期时间,或未到达过期时间的 key。

注意:过期数据不一定会被立即删除,Redis 不会实时监控每一个 key 的过期状态(否则会消耗大量CPU),而是通过特定策略"懒"删除或"批量"删除。

2. 数据删除 vs 数据淘汰

这是最容易混淆的两个概念,一句话区分:

  • 数据删除:针对「过期数据」的清理操作,核心是"删除过期的key",释放内存;

  • 数据淘汰:针对「内存满了之后」的处理操作,核心是"删除部分非过期数据",为新数据腾出内存(只有当内存达到 maxmemory 阈值时才会触发)。

简单说:删除是"清理过期垃圾",淘汰是"内存不够时腾地方"。

二、Redis 数据删除策略(清理过期数据)

Redis 没有采用"实时删除"(每一个 key 过期就立即删除),因为实时删除会导致 CPU 利用率飙升(尤其是过期 key 极多的场景),影响 Redis 核心读写性能。

实际上,Redis 采用「三种删除策略结合」的方式,兼顾 CPU 性能和内存利用率,分别是:惰性删除、定期删除、主动删除

1. 惰性删除(Lazy Expiration):最"懒"的删除,按需触发

核心逻辑

Redis 不主动监控 key 的过期时间,只有当「用户主动访问某个 key」时,才会检查该 key 是否过期:

  • 如果 key 未过期:正常返回数据;

  • 如果 key 已过期:立即删除该 key,返回 null(或不存在)。

优点

极致节省 CPU 资源:只在"访问时"才检查过期,不占用额外的 CPU 时间,对 Redis 核心读写性能几乎无影响。

缺点

内存浪费严重:如果一个过期 key 长期不被访问,它会一直占用内存,直到被访问时才会被删除。极端情况下,大量过期 key 堆积会导致内存溢出(这也是为什么需要配合其他删除策略)。

举个例子:设置 100 万个 key,过期时间为 1 小时,1 小时后所有 key 都过期,但如果没人访问这些 key,它们会一直占用内存,直到被定期删除或主动删除清理。

2. 定期删除(Periodic Expiration):折中方案,批量检查

核心逻辑

Redis 会每隔一段时间(默认 100ms,可通过配置调整),随机抽取一部分过期 key 进行检查,如果发现过期,就删除它们。具体流程:

  1. 每次执行定期删除时,从过期字典(存储所有过期 key 的字典)中随机抽取 N 个 key;

  2. 检查这些 key 是否过期,删除所有过期的 key;

  3. 如果删除的 key 数量超过 N 的 25%,则重复步骤 1(说明当前过期 key 较多,需要继续清理);否则结束本次定期删除。

关键配置

定期删除的频率由配置 hz 控制(默认 hz=10),hz 的值表示「Redis 每秒执行定期任务的次数」:

  • hz 值越大,定期删除越频繁,过期 key 清理越及时,但 CPU 占用越高;

  • hz 值越小,CPU 占用越低,但过期 key 清理越慢,内存浪费越严重。

生产环境建议:hz 保持默认 10 即可,若内存压力较大,可调整为 20(需注意 CPU 负载)。

优点

折中了 CPU 和内存:既不会像惰性删除那样浪费大量内存,也不会像实时删除那样占用过多 CPU。

缺点

存在"漏删"风险:因为是随机抽取检查,可能有部分过期 key 一直未被抽取到,从而长期占用内存(但可以通过惰性删除弥补:只要用户访问,就会被删除)。

3. 主动删除(Active Expiration):内存不足时的强制清理

核心逻辑

当 Redis 内存使用达到 maxmemory(最大内存阈值)时,会触发「主动删除」------优先删除过期 key,释放内存,避免内存溢出。

注意:主动删除是「淘汰策略的前置步骤」:当内存满时,Redis 会先尝试删除所有过期 key;如果删除完所有过期 key 后,内存仍然不足,才会执行「数据淘汰策略」(删除非过期 key)。

触发条件

只有当内存使用量 ≥ maxmemory 时,才会触发主动删除;如果内存未达到阈值,即使有大量过期 key,也只会通过惰性删除和定期删除清理。

总结:三种删除策略的协同工作

Redis 不是单一使用某一种删除策略,而是三者结合:

  1. 日常情况下,通过「惰性删除」保证 CPU 高效,避免不必要的检查;

  2. 每隔一段时间,通过「定期删除」批量清理部分过期 key,减少内存浪费;

  3. 当内存不足时,通过「主动删除」优先清理所有过期 key,为新数据腾出空间;

  4. 若主动删除后内存仍不足,则执行「数据淘汰策略」。

三、Redis 数据淘汰策略(内存满时腾空间)

当 Redis 内存使用达到 maxmemory,且删除所有过期 key 后内存仍然不足时,就会触发「数据淘汰策略」------删除部分非过期 key,为新数据腾出内存。

Redis 提供了 8 种淘汰策略(Redis 6.0+ 版本),其中常用的有 6 种,可分为「三类」:按访问频率淘汰、按时间淘汰、按随机淘汰。

先明确:淘汰策略的核心前提

  • 淘汰范围:默认只淘汰「设置了过期时间的 key」;若所有设置过期时间的 key 都被淘汰完,内存仍不足,则会淘汰「未设置过期时间的 key」(除非配置了只淘汰过期 key)。

  • 触发时机:每次执行「写操作」(set、hset、lpush 等)时,都会检查内存是否达到 maxmemory;若达到,则执行淘汰策略,直到内存低于 maxmemory,再执行写操作。

  • 核心配置:通过 maxmemory-policy 配置淘汰策略(默认策略:noeviction)。

8种淘汰策略详解(按常用程度排序)

先给出所有策略的对照表,再逐一拆解常用策略:

淘汰策略(配置值) 核心逻辑 适用场景 是否常用
allkeys-lru 淘汰所有 key 中「最近最少使用」的 key(LRU:Least Recently Used) 通用场景,大多数业务(如缓存、会话存储) ✅ 非常常用
volatile-lru 只淘汰「设置了过期时间」的 key 中,最近最少使用的 key 需要保留未过期 key(如核心配置),只淘汰临时缓存 ✅ 常用
allkeys-random 随机淘汰所有 key 中的任意一个 对 key 访问频率无要求,追求简单高效 ❌ 不常用
volatile-random 只随机淘汰「设置了过期时间」的 key 同上,且需要保留未过期 key ❌ 不常用
volatile-ttl 只淘汰「设置了过期时间」的 key 中,剩余过期时间最短(ttl 最小)的 key 希望尽快淘汰即将过期的临时缓存 ⚠️ 场景化常用
volatile-lfu 只淘汰「设置了过期时间」的 key 中,最不经常使用的 key(LFU:Least Frequently Used) key 访问频率差异大,优先保留高频访问 key ✅ 常用(Redis 4.0+ 支持)
allkeys-lfu 淘汰所有 key 中,最不经常使用的 key 通用场景,比 LRU 更精准(优先淘汰低频访问 key) ✅ 常用(Redis 4.0+ 支持)
noeviction(默认) 不淘汰任何 key,拒绝所有写操作,返回错误(读操作正常) 不允许数据丢失的场景(如核心业务数据存储) ⚠️ 特殊场景使用
重点拆解:常用策略的核心区别

日常开发中,最常用的是 allkeys-lru、volatile-lru、allkeys-lfu、volatile-lfu,这四个策略的核心区别的是「淘汰范围」和「淘汰依据」:

1. LRU vs LFU:淘汰依据的区别
  • LRU(最近最少使用):判断标准是「最后一次访问时间」------ 很久没被访问的 key,优先淘汰。

  • LFU(最不经常使用):判断标准是「一段时间内的访问次数」------ 访问频率最低的 key,优先淘汰。

举个例子:

  • keyA:每天访问 1 次,但每次访问都是最近 1 小时内;

  • keyB:每天访问 100 次,但最后一次访问是 3 天前。

LRU 会淘汰 keyB(最近最少访问),LFU 会淘汰 keyA(访问频率最低)------ 可见 LFU 更适合「访问频率差异大」的场景,能更好地保留高频访问的核心缓存。

2. allkeys vs volatile:淘汰范围的区别
  • allkeys-*:淘汰范围是「所有 key」(无论是否设置过期时间),适合「所有数据都是缓存」的场景(如商品缓存、接口缓存)。

  • volatile-*:淘汰范围是「只设置了过期时间的 key」,适合「有核心数据(未设置过期时间)和临时缓存(设置过期时间)」的场景(如核心配置 key 不设置过期,临时会话 key 设置过期)。

淘汰策略的底层实现(简化版)

很多人好奇:Redis 是如何记录 key 的访问时间/频率,实现 LRU/LFU 淘汰的?这里给出简化版原理,不用深入源码,理解即可:

  1. 对于 LRU:Redis 给每个 key 维护一个「最后访问时间戳」,淘汰时,遍历候选 key(根据淘汰范围),筛选出时间戳最小(最近最少访问)的 key 进行删除。

  2. 对于 LFU:Redis 给每个 key 维护一个「访问计数器」,每次访问 key 时,计数器加 1;每隔一段时间,计数器会衰减(避免旧的高频 key 一直占用),淘汰时,筛选出计数器最小(最不经常使用)的 key 进行删除。

注意:Redis 的 LRU/LFU 并非「严格意义上的全量排序」(全量排序会消耗大量 CPU),而是通过「采样排序」实现------每次淘汰时,随机抽取一定数量的 key(默认 5 个,可通过 maxmemory-samples 配置),在采样的 key 中选择最该淘汰的,兼顾性能和准确性。

四、核心配置实战(生产环境必看)

了解了删除和淘汰策略后,最关键的是「生产环境如何配置」,避免内存溢出或数据异常。以下是核心配置项和推荐配置:

1. 核心配置项说明

配置项 作用 推荐值
maxmemory 设置 Redis 最大可用内存(必须配置,否则内存会无限增长,导致服务器内存溢出) 根据服务器内存配置,建议设置为服务器内存的 50%-70%(如 8G 内存,设置为 4G)
maxmemory-policy 设置数据淘汰策略 通用场景:allkeys-lfu;有核心未过期 key:volatile-lfu
hz 定期删除的频率(每秒执行次数) 默认 10,内存压力大时可调整为 20
maxmemory-samples LRU/LFU 淘汰时的采样数量 默认 5,采样数量越多,淘汰越精准,但 CPU 占用越高(建议保持默认)

2. 推荐配置示例(redis.conf)

复制代码
# 设置最大内存为 4G
maxmemory 4gb

# 淘汰策略:所有 key 中最不经常使用的
maxmemory-policy allkeys-lfu

# 定期删除频率:每秒 10 次
hz 10

# LFU 采样数量:5 个
maxmemory-samples 5

3. 动态调整配置(无需重启Redis)

生产环境中,若需临时调整配置,可通过 Redis 命令动态修改(重启后失效,需同步修改 redis.conf 永久生效):

复制代码
# 动态设置最大内存为 4G
config set maxmemory 4gb

# 动态设置淘汰策略为 allkeys-lfu
config set maxmemory-policy allkeys-lfu

# 查看当前所有配置
config get *

五、常见问题与避坑指南

在使用 Redis 数据删除与淘汰策略时,很多开发者会遇到以下问题,提前规避能少走很多弯路:

1. 问题1:内存满了,Redis 拒绝写操作(返回 OOM command not allowed when used memory > 'maxmemory')

原因:淘汰策略设置为默认的 noeviction,内存满时不淘汰任何 key,拒绝所有写操作。

解决方案:将淘汰策略修改为 allkeys-lfu 或 volatile-lfu,同时检查 maxmemory 是否配置合理。

2. 问题2:大量过期 key 堆积,内存占用过高

原因:定期删除频率过低(hz 太小),且过期 key 长期不被访问(惰性删除无法触发)。

解决方案:适当提高 hz 值(如调整为 20),同时在业务层定期清理过期 key(如通过定时任务执行 DEL 命令)。

3. 问题3:核心 key 被淘汰

原因:淘汰策略设置为 allkeys-*,核心 key 未设置过期时间,但内存满时被淘汰;或核心 key 设置了过期时间,被 volatile-* 策略淘汰。

解决方案:核心 key 不设置过期时间,淘汰策略使用 volatile-lfu(只淘汰设置了过期时间的临时 key)。

4. 问题4:LRU 淘汰策略不精准

原因:maxmemory-samples 采样数量太少,导致筛选出的"最近最少使用"key 不是真正的低频 key。

解决方案:适当提高 maxmemory-samples(如调整为 10),但需注意 CPU 负载。

六、总结

Redis 数据删除与淘汰策略,核心是「平衡 CPU 性能、内存利用率和数据一致性」,记住以下核心要点,就能轻松应对生产场景:

  1. 「删除策略」是清理过期 key,三种结合:惰性删除(省 CPU)+ 定期删除(折中)+ 主动删除(内存不足时);

  2. 「淘汰策略」是内存满时腾空间,常用 allkeys-lfu(通用)和 volatile-lfu(有核心 key);

  3. 生产环境必须配置 maxmemory 和 maxmemory-policy,避免内存溢出;

  4. LRU 看"最近访问时间",LFU 看"访问频率",根据业务场景选择;

  5. 核心 key 不设置过期时间,避免被淘汰。

理解了这些策略,不仅能解决 Redis 内存相关的问题,还能在面试中从容应对相关问题(Redis 淘汰策略是后端面试高频题)。

如果需要,我还可以为你补充:

  • LRU/LFU 底层源码简化解析;

  • 过期 key 清理的监控方法;

  • 不同业务场景(缓存、会话、配置存储)的具体策略配置。

相关推荐
运维行者_4 小时前
企业无线网络监控的挑战与智能化演进趋势
大数据·运维·服务器·网络·数据库
国强_dev5 小时前
技术探讨:使用 stunnel 加密转发数据库连接时,如何获取客户端真实 IP?
数据库·网络协议·tcp/ip
@insist1235 小时前
系统规划与管理师-信息系统规划核心工作要点解析
数据库·软考·系统规划与管理师·软件水平考试·系统规划与管理工程师
超级数据查看器5 小时前
超级数据查看器 v10.0 发布
java·大数据·数据库·sqlite·安卓
数安3000天6 小时前
增量数据如何自动分类分级,避免目录“过期“?
大数据·数据库
桌面运维家6 小时前
如何用半缓存云桌面将服务器硬盘容量扩展至本地终端?
运维·服务器·缓存
南墙上的石头7 小时前
麒麟 V10 重装人大金仓 V8R6 踩坑实录(含 MySQL 兼容模式)
数据库·mysql
画中有画8 小时前
论向量数据库在项目中的应用
数据库
spider_xcxc8 小时前
Redis 数据库高质量实践指南(一)
运维·数据库·redis·oracle·云计算
l1t9 小时前
在linux和windows中解决duckdb 1.6dev版本输出执行计划报错问题
linux·运维·数据库·windows·duckdb