Redis 数据过期策略有哪 3 种?TTL 与删除机制一次讲清

编程狮(w3cschool.cn) 2026-10-07 07:05:19 浏览数 (37)
反馈

Redis 过期策略3 种删除机制怎么选?

Redis 过期策略决定了带时效的键什么时候真正从内存消失。Redis 用「惰性删除 + 定期删除」两种机制配合清理过期键,再靠内存淘汰兜底,避免内存被死键撑爆。本文基于 Redis 7 验证,把定时、惰性、定期三种删除方式讲清楚,并说明 TTL 设置与内存淘汰的触发条件。看完你能解释「为什么键过期了内存还没降」,也会避开几个最常见的缓存误区。今天这篇文章,编程狮就把这块讲透。理解 Redis 过期策略的底层取舍,能帮你在上线前就把内存曲线算清楚,而不是等告警才手忙脚乱地排查。

先看结论

机制 触发时机 优点 代价
定时删除 到期立刻删 内存最及时 CPU 压力大,Redis 不用
惰性删除 被访问时才删 零额外 CPU 不访问就一直占内存
定期删除 周期性抽样删 折中方案 有概率清不干净

一句话:Redis 实际只用惰性删除加定期删除,内存淘汰是最后兜底。

一、先弄清楚:过期键为什么会占着内存

你给一个键设了 30 秒过期,到点后它不会立刻消失,内存也不一定马上降。这不是 Bug,而是 Redis 故意用「惰性 + 定期」组合换 CPU 性能。先读 Redis 教程 建立键与过期的基础,再看机制更顺。

1.1 TTL 是什么

TTL 过期时间就是键的存活倒计时。用 EXPIRE 设置秒数后,键到点变为逻辑过期,但物理删除要看下面的删除机制。

1.2 为什么要三种删除配合

单纯定时删除 CPU 吃不消,单纯惰性删除内存回收慢。Redis 选择惰性删除兜底正确性、定期删除做常规清扫,再用内存淘汰防止极端堆积。

二、惰性删除与 TTL 查询

惰性删除的逻辑很简单:键被访问时才检查是否过期,过期就当场删除并返回空。它零额外 CPU,但代价是「没人访问的过期键会一直占着内存」。

# 设置 30 秒过期
SET code:login:1001 "a1b2c3"
EXPIRE code:login:1001 30

# 查看还剩多少秒,-2 表示已过期被删
TTL code:login:1001

TTL 过期时间到达后,如果一直不访问,这个键就静默躺在内存里。更多命令细节见 Redis 详解教程。

TTL 查询与惰性删除时序

三、定期删除:周期性抽样清理

定期删除由 Redis 后台定时执行:每隔一段时间随机抽一批带过期时间的键,删掉其中已过的,如果过期比例高就再抽一轮。它是对惰性删除的补漏,避免过期键永远不被访问。

# 相关配置(redis.conf 倾向性示意,非必须手改)
# hz 控制每秒定期删除的触发频率,默认 10
hz 10
# 单轮抽样上限
# ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 默认 20

定期删除不是全量扫描,所以「抽到的才清、没抽到的等下轮」,这也是过期键偶尔残留的原因。它和惰性删除配合,既控 CPU 又保内存。

四、内存淘汰与常见误区

当定期删除赶不上写入速度、内存逼近上限时,Redis 启用内存淘汰:按 maxmemory-policy 决定哪些键先走。常见策略有 noeviction(报错)、allkeys-lru(全量最近最少用)、volatile-ttl(优先淘汰快过期的)。

# 设置最大内存与淘汰策略(示例值)
CONFIG SET maxmemory 2gb
CONFIG SET maxmemory-policy allkeys-lru

内存淘汰不等于过期删除,它是「内存满了」时的兜底,和 TTL 过期策略是两套机制,别混为一谈。

4.1 三个最容易踩的坑

现象 原因 修复
键过期了内存没降 靠惰性删除,未被访问 正常,定期删除会逐步回收,或主动访问触发
设了过期却还被读到旧值 从库同步延迟 / 主从不一致 读写分离场景以主库 TTL 为准
内存满后写入报错 用了 noeviction 又没淘汰 改 allkeys-lru 等策略

内存淘汰策略对比

动手验证清单

按下面步骤在本机观察过期键的真实行为,把 Redis 过期策略的取舍看明白(命令基于 Redis 7,未在本机执行,请按你的版本核对输出):

  1. 前置安装:先装好 Redis 并启动服务,redis-cli ping 返回 PONG 表示就绪,确认连接正常再继续后面的命令,连不上先核对配置文件 bind 与端口。
  2. 运行设置:用 SET code:login:1001 "a1b2c3" 写入再 EXPIRE 设 30 秒,预期 TTL 返回递减的秒数,到点后变 -2 表示键已被删,这是 TTL 过期时间最直观的验证。
  3. 配置与检查:用 CONFIG GET maxmemory-policy 查看当前内存淘汰策略,检查 Redis 过期策略是否和你预期一致;调 hz 参数可以改变定期删除的触发频率。
  4. 验证惰性删除:键过期后不访问,用 INFO memory 观察 used_memory 不会立刻下降;主动访问后才释放,这正是 Redis 过期策略用惰性删除换 CPU 的体现,也是「内存没降」现象的根因。
  5. 失败处理与排错:若内存满后写入报错,多半是默认 noeviction 所致,改成 allkeys-lru 即可;若过期键迟迟不回收,适当调高 hz 让定期删除更积极;若从库读到旧值,是以主库 TTL 为准的同步延迟。适用边界:纯缓存设 allkeys-lru,重要数据加 volatile-ttl,别让默认策略裸奔上线。

总结

Redis 过期策略由「惰性删除 + 定期删除」组合完成,定时删除只作理论对照。TTL 过期时间到点后键只是逻辑过期,物理删除发生在被访问时或定期抽样时;内存淘汰则是内存触顶时的独立兜底。

要点带走:

  • 惰性删除保证正确性,定期删除做常规清扫,两者配合控 CPU 也保内存;
  • 过期键偶尔残留是正常的,不是没生效;
  • 内存淘汰与过期删除是两回事,上线必须设 maxmemory-policy。

下一步可结合业务设好最大内存与淘汰策略,再压测观察内存曲线。

延伸学习

这块知识系统补齐,按这个顺序来:

  1. 过期后怎么彻底释放,Redis 过期清除 给了实操视角;
  2. 断电后过期数据怎么办,Redis 持久化方案 讲了安全边界;
  3. 想搞懂它为什么快,Redis 缓存入门 补了加速原理。

常见问题

Q:键过期了为什么内存没立刻降?

A:因为 Redis 用惰性删除,过期键只有被访问时才真正删除,未被访问就暂时留在内存。定期删除会周期性抽样清理,所以通常会逐步回落,属于正常行为。

Q:内存淘汰和过期删除是一回事吗?

A:不是。过期删除处理「到点的键」,内存淘汰处理「内存满了先扔谁」。即使没有过期键,写入量大到触顶也会触发内存淘汰,二者机制独立。

Q:生产环境该用哪种淘汰策略?

A:缓存场景常用 allkeys-lru,让最久没用的键先走;若只想淘汰带过期的键,用 volatile-ttl。关键是必须显式设置,默认的 noeviction 会在内存满时直接拒绝写入。

0 人点赞