Redis数据删除与淘汰策略:从原理到实战

作者:技术拾光时间:2026-06-07 08:46:13浏览:163

Redis采用惰性删除、定期删除及主动删除协同清理过期数据。内存达上限时,触发淘汰策略(如allkeys-lfu、volatile-lfu)删除非过期key。生产需配置maxmemory和maxmemory-policy,避免内存溢出或数据丢失。

Redis 以高性能闻名,所有数据都在内存中运行。但内存资源有限,用一分少一分。因此核心问题随之而来:过期数据如何删除?内存满载后新数据如何存放?

Redis数据删除与淘汰策略:从原理到实战

这两个问题分别对应 Redis 的数据删除策略和数据淘汰策略。一个负责清理过期数据,一个负责在内存不足时腾出空间。两者配合决定了 Redis 的性能和内存利用率。虽然听起来简单,但实际工作中不少人容易混淆这两个概念。一旦配置混乱,就可能引发内存溢出、数据丢失或性能问题。

本文将从基础概念铺垫、策略细节拆解、底层原理到实战配置逐一讲解。无论是面试突击还是生产排障,都能直接使用。

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

在讲解具体策略之前,需要先明确两个基础概念,否则后续内容容易混淆。

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

Redis 允许通过 EXPIRE、PEXPIRE 等命令为 key 设置过期时间。过期数据是指已到达预设时间但尚未被删除的 key;非过期数据则是指未设置过期时间,或者尚未到达过期时间的 key。

关键点在于:过期不代表立即删除。Redis 不会实时监控每个 key 的过期状态,否则会大量消耗 CPU 资源。它采用“懒删除”或“批量删除”的思路。

2. 数据删除 vs 数据淘汰

这两个概念最容易混淆,用一句话概括:

  • 数据删除:针对“过期数据”的清理,核心是删除过期的 key,释放内存。
  • 数据淘汰:针对“内存满载”后的处理,核心是删除部分非过期的 key,为新数据腾出空间(仅在内存达到 maxmemory 阈值时触发)。

简而言之:删除是清理过期垃圾,淘汰是内存不足时被迫腾空间。

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

Redis 并未采用“实时删除”机制,即每个 key 过期后立即删除。原因很简单:实时删除会导致 CPU 利用率飙升,尤其是在过期 key 数量较多时,会严重影响 Redis 的核心读写性能。

因此,Redis 采用了三种删除策略结合的方式,在 CPU 性能和内存利用率之间寻找平衡:惰性删除、定期删除、主动删除。

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

核心逻辑

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

  • 如果未过期,正常返回数据。
  • 如果已过期,直接删除并返回 null(或提示该 key 不存在)。

优点

节省 CPU 资源:仅在访问时检查,不额外占用 CPU 时间,对核心读写性能几乎无影响。

缺点

容易浪费内存:如果某个过期 key 一直未被访问,就会一直占用内存。极端情况下,大量过期 key 堆积会迅速耗尽内存,这也是必须配合其他删除策略的原因。

典型场景:假设设置了 100 万个 key,过期时间均为 1 小时。1 小时后所有 key 过期,但只要无人访问,这些 key 就会一直占用内存,直到定期删除或主动删除来处理。

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

核心逻辑

Redis 每隔一段时间(默认 100 毫秒,可配置),随机抽取一批过期 key 进行检查,发现过期则删除。具体流程如下:

  • 每次执行定期删除时,从过期字典(存储所有设置了过期时间的 key)中随机抽取 N 个 key;
  • 检查这些 key 是否过期,并删除所有过期的 key;
  • 如果删除的 key 数量超过 N 的 25%,说明当前过期 key 较多,则继续执行新一轮检查;否则本次定期删除结束。

关键配置

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

  • hz 越大,定期删除越频繁,过期 key 清理越及时,但 CPU 消耗也越高。
  • hz 越小,CPU 节省越多,但过期 key 清理越慢,内存浪费更严重。

生产环境建议保持默认值 10。如果内存压力较大,可适当调至 20,但需关注 CPU 负载。

优点

在 CPU 和内存之间取得平衡:既不像惰性删除那样过度浪费内存,也不像实时删除那样导致 CPU 过载。

缺点

存在“漏删”可能:由于是随机抽样,某些过期 key 可能一直未被抽到,从而持续占用内存。不过惰性删除可起到补充作用:一旦有人访问该 key,就会被删除。

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

核心逻辑

当 Redis 内存使用量达到 maxmemory 阈值时,会触发“主动删除”:先清理所有过期的 key,释放内存,防止内存溢出。

需要注意的是:主动删除是“淘汰策略的前置步骤”。内存满载时,Redis 会先尝试删除所有过期 key;如果清理后内存仍然不足,才会启动“数据淘汰策略”(即删除非过期的 key)。

触发条件

仅在内存使用量 ≥ maxmemory 时触发。如果内存未达到阈值,即使过期 key 堆积严重,也只会依赖惰性删除和定期删除处理。

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

Redis 并非依赖单一策略,而是三管齐下:

  • 日常依靠“惰性删除”保证 CPU 高效运行,减少无效操作。
  • 定期通过“定期删除”批量扫描,降低内存浪费。
  • 内存紧张时由“主动删除”先行清理过期 key,腾出空间。
  • 若清理过期 key 后依然不足,则进入“数据淘汰策略”阶段。

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

当 Redis 内存使用量达到 maxmemory,且过期 key 全部删除后内存仍然不足时,就需要启动“数据淘汰策略”——删除部分非过期的 key,为新数据腾出空间。

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

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

  • 淘汰范围:默认仅淘汰“设置了过期时间的 key”。如果设置了过期时间的 key 全部淘汰后仍不够,则会淘汰“未设置过期时间的 key”(除非配置为仅淘汰过期 key)。
  • 触发时机:每次执行“写操作”(如 set、hset、lpush 等)时,都会检查内存是否达到 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 淘汰。以下为简化原理(无需深入源码):

  • 对于 LRU:Redis 为每个 key 维护一个“最后访问时间戳”。淘汰时,在候选 key 中遍历,选择时间戳最小的(即最近最少访问的)进行删除。
  • 对于 LFU:Redis 为每个 key 维护一个“访问计数器”。每次访问 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-samplesLRU/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。

解决方案:适当提高 maxmemoy-samples(例如调至 10),但需关注 CPU 负载。

六、总结

Redis 数据删除与淘汰策略,核心在于平衡 CPU 性能、内存利用率和数据一致性三方面。牢记以下几点,生产场景基本不会出现问题:

  • “删除策略”负责清理过期 key,三种策略协同工作:惰性删除(节省 CPU)+ 定期删除(折中方案)+ 主动删除(内存不足时的最后防线)。
  • “淘汰策略”负责内存满载时腾出空间,常用 allkeys-lfu(通用场景)和 volatile-lfu(存在核心 key 的场景)。
  • 生产环境必须配置 maxmemory 和 maxmemory-policy,否则内存迟早溢出。
  • LRU 关注“最近访问时间”,LFU 关注“访问频率”,根据业务场景选择。
  • 核心 key 不应设置过期时间,从而避免在淘汰时被误删。

掌握这些策略,不仅能有效解决生产环境的内存问题,也能在面试中从容应对——Redis 淘汰策略是后端面试的高频考点。