Skip to content

第五章 Key 管理与过期策略

本章围绕三个问题:Key 怎么命名和管理过期后 Redis 怎么删内存满了怎么办。掌握这三点,日常开发与排障会轻松很多。


5.1 Key 的命名规范

推荐格式:业务:对象:id

把「谁、什么、哪一条」写进名字里,便于阅读、排查和按前缀批量扫描。

推荐示意:

  user:1001:name     用户 1001 的姓名
  user:1001:profile  用户 1001 的资料
  order:20240324001:items   订单下的明细(可再细分)
组成部分含义示例
业务域模块或业务线userordercache
对象类型存的实体sessioncart
标识主键或业务单号100120240324001
字段(可选)具体属性或子集合nameitems

好的命名 vs 坏的命名

类型示例说明
user:1001:name一眼能看出业务、实体、id、字段
cache:product:sku:88392前缀统一,方便 SCAN user:* 等模式
ax1data无业务语义,难以维护
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返回 stringlisthash
RENAME key newkey改名;RENAMENX 仅当 newkey 不存在时成功
DEL key [key ...]删除一个或多个 key

查找 Key:KEYSSCAN

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 更短(更快过期)的

选择建议(简要)

场景可考虑
缓存,允许丢任意 keyallkeys-lruallkeys-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 日志分别是什么、各自优缺点,以及如何在「丢一点数据」与「性能」之间做选择,帮助你在部署和备份方案上有清晰思路。

坚持是一种品格