首页 / Redis 入门教程 / 键管理与过期策略

Redis 入门教程

键管理与过期策略

本教程共 40 篇 · 第 16 篇 · 更新于 2026-08-02

rediskeysscanexpirettl键管理过期策略惰性删除定期删除

16. 键管理与过期策略

本节目标

  • 掌握键的通用命令:EXISTS / DEL / UNLINK / TYPE / RENAME / DUMP
  • 理解 KEYS 的风险,掌握安全的遍历方式 SCAN
  • 掌握过期控制:EXPIRE / PEXPIRE / EXPIREAT / TTL / PTTL / PERSIST
  • 理解 Redis 的过期删除策略:惰性删除 + 定期删除
  • 用「批量删除匹配 key」「给缓存设过期」等实战巩固

到目前为止,我们学的都是「某种数据类型怎么用」。但所有数据类型都共享一个统一的抽象:key。Redis 是 key-value 数据库,每个 key 都指向一个值(String/Hash/Set……),因此有一组「与类型无关」的通用键管理命令。本章讲这些命令,以及「key 怎么过期、过期后怎么被清理」这套机制。

16-1 判断、删除、查看类型

EXISTS 判断 key 是否存在(可一次传多个,返回存在的个数):

命令:

127.0.0.1:6379> SET user:1 "tom"
127.0.0.1:6379> EXISTS user:1 nokey

输出:

OK
(integer) 1

TYPE 查看 key 对应值的类型(对不存在的 key 返回 none):

命令:

127.0.0.1:6379> TYPE user:1

输出:

string

DEL 删除一个或多个 key,返回成功删除的数量。UNLINK 与它功能相同,但异步释放内存(把删除动作交给后台线程),对大 key 更友好、不会阻塞主线程:

命令:

127.0.0.1:6379> DEL user:1
127.0.0.1:6379> UNLINK bigkey:cache

输出:

(integer) 1
(integer) 1

RENAME 改名(RENAMENX 仅当新名不存在才改),DUMP 序列化、RESTORE 还原(用于迁移),RANDOMKEY 随机返回一个 key。

16-2 遍历键:远离 KEYS,使用 SCAN

KEYS pattern 能按通配符找出所有匹配的 key(如 KEYS user:*)。但它有致命问题:会一次性遍历全库所有 key,数据量大时长时间阻塞服务器,生产环境禁用。

安全的替代是 SCAN——基于游标的增量式遍历,每次只返回一小批,不会阻塞:

命令:

127.0.0.1:6379> SCAN 0 MATCH user:* COUNT 100

输出:

1) "34"
2) 1) "user:1001"
   2) "user:1002"

返回的第一行是「下一次游标」(为 0 时表示遍历结束),第二行是本轮匹配的 key 列表。MATCH 过滤模式,COUNT 是「每轮提示数量」(并非严格精确条数)。集合、哈希、有序集合也都有对应的 SSCAN / HSCAN / ZSCAN,用于安全遍历大集合内部元素。

16-3 过期控制:给 key 设「寿命」

给 key 设置生存时间(TTL)是缓存的核心机制。命令分秒级与毫秒级:

  • EXPIRE key seconds / PEXPIRE key ms:相对当前「多少秒/毫秒后过期」。
  • EXPIREAT key unix-seconds / PEXPIREAT key unix-ms:到指定 Unix 时间戳过期。
  • TTL key / PTTL key:查看剩余生存时间(秒/毫秒);-1 表示永不过期,-2 表示 key 不存在。
  • PERSIST key:移除过期时间,让 key 永久存在。

命令:

127.0.0.1:6379> SET session:1001 "tok" EX 3600
127.0.0.1:6379> TTL session:1001
127.0.0.1:6379> PERSIST session:1001
127.0.0.1:6379> TTL session:1001

输出:

OK
(integer) 3597
(integer) 1
(integer) -1

注意:对 key 执行 SET(不带 KEEPTTL)、RENAME 等会清除 TTL;而 INCRHSET 等「改值不改键」的命令通常不影响 TTL。哈希还支持「字段级过期」(field expiration),自 Redis 7.4.0 引入(8.x 继续支持),是过期能力的增强之一。

16-4 过期后怎么被清理:惰性删除 + 定期删除

一个很自然的问题:key 过期了,Redis 是立刻删除它吗?不是立刻。Redis 采用两种机制配合:

  1. 惰性删除(Lazy Expiration):当客户端访问某个 key 时,Redis 才检查它是否已过期,过期则当场删除并返回「不存在」。优点:零额外开销;缺点:如果过期 key 一直没人访问,它会一直占着内存。
  2. 定期删除(Active Expiration):Redis 服务器会在后台周期性地、随机抽样一批带 TTL 的 key,把其中已过期的删除。抽样数量与频率受 active-expire-effort(默认 1,越大清理越积极)等控制,避免在过期 key 很多时一次性扫描卡顿。

两种机制互补:惰性删除兜住「被访问的过期 key」,定期删除兜底「长期无人访问的过期 key」,在「CPU 开销」与「内存回收及时性」之间取得平衡。

提示:Redis 8.x 在过期清理上持续做了性能与自适应方面的优化(如基于 CPU 配额的自适应定期删除、active-expire-effort 调控扫描强度),能在大量 key 同时过期时减少主线程抖动。具体默认值以你所用 8.x 版本的 redis.conf 为准,本教程正文统一以 Redis 8.x(最新稳定版)为准。

16-5 实战:批量删除匹配 key

想删除一批符合模式的 key,不要KEYS + 客户端循环 DEL(会阻塞且增加往返)。推荐两条路:

  • SCAN + UNLINK 分批删(脚本里游标迭代,每批 UNLINK);
  • 或用 redis-cli --scan --pattern "cache:*" | xargs redis-cli UNLINK(利用 redis-cli 的 --scan 流式遍历)。

例如给缓存统一设过期、避免堆积:

命令:

127.0.0.1:6379> SET cache:product:100 EX 300
127.0.0.1:6379> EXPIRE cache:product:100 600

输出:

OK
(integer) 1

16.x 键命名、数据库编号与大 key 检测

键管理里有一件容易被忽视但影响很大的事:键命名规范。Redis 是扁平的单层 key 空间(没有目录),所以习惯用「冒号分隔的语义前缀」来模拟命名空间,例如 user:1001:profilecache:product:888stream:orders。好的命名既方便用 SCAN / KEYS 模式排查,也方便按业务批量清理。同时应避免把超长随机串直接当 key(既占内存也难排查),避免在 key 里拼入会无限增长的维度(否则 key 数量爆炸)。

关于「数据库编号」:Redis 默认有 16 个逻辑库(编号 0–15),可用 SELECT n 切换。但生产环境一般只用 db 0,不同业务用 key 前缀区分;滥用多库会让备份、迁移、监控都更复杂。真正需要隔离时,更推荐用不同的 Redis 实例或不同的逻辑集群。

另一件与「键管理」强相关的是大 key 问题:单个 value 过大(如一个超大 Hash、超长 Stream、巨型 String)会导致删除/序列化/迁移时长时间阻塞主线程。Redis 8.x 提供 redis-cli --bigkeys 扫描、以及 INFO 里的键空间统计、COMMAND/MEMORY USAGE key 等工具来定位大 key;发现后应拆分(如把大 Hash 按字段哈希成多个小 Hash)或用 UNLINK 异步删除。键管理与内存健康往往是同一件事的两面,第 17 章(内存淘汰)会继续展开。

16-6 常见误区

  • 误区:生产环境可以用 KEYS 查 key。 KEYS 会全库遍历、长时间阻塞,生产务必用 SCAN
  • 误区:TTL 返回 -1 就是 key 不存在。 -1 是「存在且永不过期」,-2 才是「不存在」,两者不同。
  • 误区:过期 key 会立刻从内存消失。 实际靠惰性 + 定期删除清理,可能有短暂滞留。
  • 误区:RENAME 后 TTL 还在。 RENAME 会保留原 key 的 TTL(把过期时间一起带走),但 SET(不带 KEEPTTL)会清除 TTL,使用时需注意。
  • 误区:删除大 key 用 DEL 无影响。 大 key 用 DEL 可能短时间阻塞,优先用 UNLINK 异步释放。

16-7 小结

  • 通用键命令:EXISTS / DEL / UNLINK(异步)/ TYPE / RENAME(RENAMENX) / DUMP / RESTORE
  • 遍历:禁用 KEYS,用 SCAN(及其类型专属的 SSCAN/HSCAN/ZSCAN)增量遍历。
  • 过期:EXPIRE/PEXPIRE/EXPIREAT/PEXPIREATTTL/PTTLPERSISTSETEX/KEEPTTL 也常用。
  • 清理机制:惰性删除(访问时检查)+ 定期删除(后台抽样),Redis 8.x 做了自适应优化。
  • 用武之地:缓存过期、批量安全删除、键空间巡检。

提示:关于版本——本教程正文统一以 Redis 8.x(最新稳定版)为准;官方 redis.io 下载页另标 8.8 为 “Latest stable”,而 GitHub 上 redis/redis 的最新发布 tag 为 8.10.0,二者同属 8.x,命令与类型差异对教材影响极小。