第五章 Key 管理与过期策略
本章围绕三个问题:Key 怎么命名和管理、过期后 Redis 怎么删、内存满了怎么办。掌握这三点,日常开发与排障会轻松很多。
5.1 Key 的命名规范
推荐格式:业务:对象:id
把「谁、什么、哪一条」写进名字里,便于阅读、排查和按前缀批量扫描。
推荐示意:
user:1001:name 用户 1001 的姓名
user:1001:profile 用户 1001 的资料
order:20240324001:items 订单下的明细(可再细分)| 组成部分 | 含义 | 示例 |
|---|---|---|
| 业务域 | 模块或业务线 | user、order、cache |
| 对象类型 | 存的实体 | session、cart |
| 标识 | 主键或业务单号 | 1001、20240324001 |
| 字段(可选) | 具体属性或子集合 | name、items |
好的命名 vs 坏的命名
| 类型 | 示例 | 说明 |
|---|---|---|
| 好 | user:1001:name | 一眼能看出业务、实体、id、字段 |
| 好 | cache:product:sku:88392 | 前缀统一,方便 SCAN user:* 等模式 |
| 坏 | a、x1、data | 无业务语义,难以维护 |
| 坏 | user1001name | 无分隔,id 与字段粘连,易误读 |
| 坏 | 过长且无结构 | 浪费内存,命令行里也难读 |
小建议:
- 统一使用小写和固定分隔符(常见为
:),团队内写一份简短约定即可。 - 避免在 Key 里塞特别长的动态字符串;特别长的标识可哈希缩短后再拼进名字。
5.2 常用 Key 操作命令
下面命令均在 redis-cli 中演示。请先能连上本机 Redis(默认 127.0.0.1:6379)。
设置与过期相关
text
127.0.0.1:6379> SET user:1001:name "Alice"
OK
127.0.0.1:6379> EXPIRE user:1001:name 60
(integer) 1
127.0.0.1:6379> TTL user:1001:name
(integer) 58| 命令 | 作用 |
|---|---|
EXPIRE key seconds | 为已有 key 设置秒级过期时间 |
PEXPIRE key ms | 毫秒级过期 |
TTL key | 剩余秒数;-1 表示未设置过期;-2 表示 key 不存在 |
PTTL key | 剩余毫秒数 |
PERSIST key | 去掉过期时间,变为持久 key |
存在性、类型、改名、删除
text
127.0.0.1:6379> EXISTS user:1001:name
(integer) 1
127.0.0.1:6379> TYPE user:1001:name
string
127.0.0.1:6379> RENAME user:1001:name user:1001:display_name
OK
127.0.0.1:6379> DEL user:1001:display_name
(integer) 1| 命令 | 作用 |
|---|---|
EXISTS key [key ...] | 存在返回 1(或多个存在个数),否则 0 |
TYPE key | 返回 string、list、hash 等 |
RENAME key newkey | 改名;RENAMENX 仅当 newkey 不存在时成功 |
DEL key [key ...] | 删除一个或多个 key |
查找 Key:KEYS 与 SCAN
text
127.0.0.1:6379> KEYS user:*
1) "user:1001:name"text
127.0.0.1:6379> SCAN 0 MATCH user:* COUNT 10
1) "0"
2) 1) "user:1001:name"| 命令 | 适用场景 | 注意 |
|---|---|---|
KEYS pattern | 仅小数据量、本机调试 | 会阻塞,生产慎用 |
SCAN cursor [MATCH] [COUNT] | 生产环境遍历 | 游标迭代,需多次调用直至游标回到 0 |
记忆口诀: 线上查 key 用 SCAN,不要用 KEYS 扫全库。
5.3 过期删除策略
过期时间到了以后,key 不会立刻从内存里消失,Redis 用两种方式配合清理。
惰性删除(Lazy expiration)
访问 key 时
|
v
已过期? ----是----> 立刻删除,对客户端表现为「没有这个 key」
|
否
|
v
正常返回数据- 含义: 只有读/写命中这个 key 时,才检查是否过期,过期则删。
- 优点: 不占用额外 CPU 去扫全库。
- 缺点: 若 key 一直没人访问,可能长期占内存(直到被定期删除或淘汰策略处理)。
定期删除(Active expiration)
定时任务(抽样)
|
v
随机抽一批 key 检查过期
|
v
过期的删掉,未过期则放过- 含义: Redis 周期性地随机抽查一部分 key,删掉其中已过期的。
- 优点: 能慢慢「消化」那些不再被访问的过期 key。
- 缺点: 单次抽查有限,不能保证某一时刻所有过期 key 都已删除。
两种策略为什么要配合?
惰性删除 定期删除
(访问时清理) (后台抽样清理)
\ /
\ /
v v
「尽快对用户一致」 「慢慢回收冷数据内存」- 惰性删除保证:你用到的 key 一定是「未过期或已被当作不存在」的,语义正确。
- 定期删除减轻:大量过期但永不访问的 key 长期占内存的问题。
- 二者结合:在CPU 开销与内存回收之间取得平衡;若仍内存紧张,还需依赖下一节的 maxmemory 淘汰策略。
5.4 内存淘汰策略(maxmemory-policy)
当 Redis 配置了 maxmemory(最大使用内存),且数据已达到上限时,新写入可能触发淘汰:按策略删掉一些 key 腾出空间。
配置在 redis.conf 中,例如:
text
maxmemory 256mb
maxmemory-policy allkeys-lru八种策略一览
| 策略 | 淘汰范围 | 规则简述 |
|---|---|---|
noeviction | — | 不淘汰;内存满时写命令报错(读仍可用) |
allkeys-lru | 所有 key | 从全部 key 里淘汰最近最少使用的 |
volatile-lru | 仅带过期时间的 key | 同上,但只考虑设置了 TTL 的 key |
allkeys-lfu | 所有 key | 淘汰使用频率最低的(Redis 4.0+) |
volatile-lfu | 仅带过期时间的 key | 同上,范围限 TTL key |
allkeys-random | 所有 key | 随机淘汰 |
volatile-random | 仅带过期时间的 key | 随机,范围限 TTL key |
volatile-ttl | 仅带过期时间的 key | 优先淘汰 TTL 更短(更快过期)的 |
选择建议(简要)
| 场景 | 可考虑 |
|---|---|
| 缓存,允许丢任意 key | allkeys-lru 或 allkeys-lfu(访问模式稳定时 LFU 更贴「热点」) |
| 既有持久重要数据又有缓存,希望只丢缓存 | volatile-*,且重要数据不设 TTL 或单独实例 |
| 绝不自动删数据,宁愿写失败 | noeviction(需自己控内存或扩容) |
| 对 LRU/LFU 不敏感、实现简单 | allkeys-random / volatile-random |
注意: volatile-* 在「没有任何带 TTL 的 key」时,行为会退化为与 noeviction 类似(无法按策略淘汰),容易踩坑;设计时要保证有可被淘汰的 TTL key。
本章小结
| 小节 | 核心要点 |
|---|---|
| 5.1 命名 | 推荐 业务:对象:id[:字段],语义清晰、便于扫描 |
| 5.2 命令 | EXPIRE/TTL/PERSIST 管过期;EXISTS/TYPE/RENAME/DEL 管生命周期;生产用 SCAN 代替 KEYS |
| 5.3 过期删除 | 惰性(访问时删)+ 定期(抽样删),平衡正确性与内存、CPU |
| 5.4 淘汰策略 | 配 maxmemory 后由 maxmemory-policy 决定在内存满时删谁;缓存常用 allkeys-lru/allkeys-lfu |
下一章预告
第六章 将围绕 Redis 持久化 展开:RDB 快照与 AOF 日志分别是什么、各自优缺点,以及如何在「丢一点数据」与「性能」之间做选择,帮助你在部署和备份方案上有清晰思路。