01 过期时间与内存淘汰
内存是有限的。本章回答两个问题:过期的 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. 小结(面试就考这几句)
- 过期删除 = 惰性删除 + 定期删除,过期不等于立刻消失
- 不带
EX的set会清掉原有过期时间 - 内存满了走淘汰策略,缓存场景推荐
allkeys-lru - 默认策略
noeviction会让写入报错,生产环境要显式配置
下一章:Redis 重启后数据还在吗 👉 02 持久化:RDB 与 AOF