键管理与过期策略
本教程共 40 篇 · 第 16 篇 · 更新于 2026-08-02
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;而 INCR、HSET 等「改值不改键」的命令通常不影响 TTL。哈希还支持「字段级过期」(field expiration),自 Redis 7.4.0 引入(8.x 继续支持),是过期能力的增强之一。
16-4 过期后怎么被清理:惰性删除 + 定期删除
一个很自然的问题:key 过期了,Redis 是立刻删除它吗?不是立刻。Redis 采用两种机制配合:
- 惰性删除(Lazy Expiration):当客户端访问某个 key 时,Redis 才检查它是否已过期,过期则当场删除并返回「不存在」。优点:零额外开销;缺点:如果过期 key 一直没人访问,它会一直占着内存。
- 定期删除(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:profile、cache:product:888、stream: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/PEXPIREAT、TTL/PTTL、PERSIST;SET的EX/KEEPTTL也常用。 - 清理机制:惰性删除(访问时检查)+ 定期删除(后台抽样),Redis 8.x 做了自适应优化。
- 用武之地:缓存过期、批量安全删除、键空间巡检。
提示:关于版本——本教程正文统一以 Redis 8.x(最新稳定版)为准;官方 redis.io 下载页另标 8.8 为 “Latest stable”,而 GitHub 上 redis/redis 的最新发布 tag 为 8.10.0,二者同属 8.x,命令与类型差异对教材影响极小。