跳到主要内容

3.1 过期时间与内存淘汰

内存是有限的。本章回答两个问题:过期的 key 是什么时候被真正删掉的?内存满了 Redis 会怎么办? 这两个问题也是面试的常客。

1. 回顾:怎么设置过期时间

expire key 60 # 已有 key 设置 60 秒过期
set key value EX 60 # 存的时候顺便设置(推荐)
ttl key # 查看剩余时间(-1 永久,-2 不存在)
persist key # 取消过期,变永久

一个容易踩的坑:对已有 key 再次 set,过期时间会被清掉

127.0.0.1:6379> set token abc EX 100
OK
127.0.0.1:6379> ttl token
(integer) 98
127.0.0.1:6379> set token xyz # 没带 EX 的 set
OK
127.0.0.1:6379> ttl token
(integer) -1 # 过期时间没了,变永久了!

所以更新带过期时间的 key 时,要么重新带上 EX,要么用 keepttl 选项:set token xyz keepttl

2. 过期的 key 是什么时候被删除的?

直觉上以为"一到点就删",其实不是。给每个 key 挂个定时器太浪费资源,Redis 采用两种策略配合:

策略一:惰性删除(Lazy Expiration)

访问 key 的时候才检查它过没过期,过期了就顺手删掉并返回 nil。

  • 优点:零额外开销
  • 缺点:如果一个过期 key 永远没人访问,它就一直赖在内存里

策略二:定期删除(Active Expiration)

Redis 每隔 100 毫秒随机抽查一批设置了过期时间的 key,把其中已过期的删掉。 如果抽查发现过期比例很高,就再抽一轮,直到比例降下来。

  • 优点:能清理没人访问的过期 key
  • 缺点:是抽查不是全量,仍可能有漏网之鱼

两种策略结合,大部分过期 key 都能被及时清理。但注意结论:过期 ≠ 立刻从内存消失。极端情况下,过期但未被删除的 key 依然占着内存——这就引出了下一个保底机制。

3. 内存满了怎么办:内存淘汰策略

Redis 可以配置最大内存:

maxmemory 2gb

当内存用满,再写入新数据时,Redis 按 maxmemory-policy 配置的策略处理,共 8 种:

策略行为
noeviction(默认)谁也不删,直接对写命令报错
allkeys-lru所有 key 中淘汰最久没被访问的 ⭐
allkeys-lfu从所有 key 中淘汰访问频率最低的
allkeys-random从所有 key 中随机淘汰
volatile-lru只从设了过期时间的 key 中淘汰最久没访问的
volatile-lfu只从设了过期时间的 key 中淘汰频率最低的
volatile-random只从设了过期时间的 key 中随机淘汰
volatile-ttl只从设了过期时间的 key 中淘汰最快要过期的

记忆方法:前缀 = 淘汰范围allkeys 全部 / volatile 仅带过期时间的),后缀 = 挑选算法(LRU 最久未用 / LFU 最少使用 / random 随机 / ttl 最快过期)。

怎么选?

  • 纯当缓存用(数据丢了可以从数据库重建)→ allkeys-lru,最常用
  • 既有缓存又有不能丢的数据 → volatile-lru,给缓存 key 设过期时间,重要 key 不设
  • 默认的 noeviction 在生产上往往不合适——内存一满,业务写入直接报错
maxmemory 2gb
maxmemory-policy allkeys-lru

💡 LRU(Least Recently Used):最近最少使用,"很久没人碰的先扔"。 LFU(Least Frequently Used):最不经常使用,"访问次数少的先扔"。 新手记住 LRU 即可,它是缓存领域最经典的算法。

4. 查看当前内存状况

127.0.0.1:6379> info memory
used_memory_human:1.20M # 当前用了多少
maxmemory_human:2.00G # 上限
maxmemory_policy:allkeys-lru # 淘汰策略

# 查看单个 key 占多少内存
127.0.0.1:6379> memory usage user:1001
(integer) 88

5. 小结(面试就考这几句)

  1. 过期删除 = 惰性删除 + 定期删除,过期不等于立刻消失
  2. 不带 EXset清掉原有过期时间
  3. 内存满了走淘汰策略,缓存场景推荐 allkeys-lru
  4. 默认策略 noeviction 会让写入报错,生产环境要显式配置

下一章:Redis 重启后数据还在吗 👉 3.2 持久化:RDB 与 AOF