Appearance
Redis 内存、过期与淘汰策略:为什么明明设置了过期,内存还是会涨
很多 Redis 线上问题,看起来像“容量不够”,但真正往下看通常会发现是:
- Key 设计有问题
- 过期策略理解有误
- 淘汰策略不适合当前业务
先说结论
Redis 内存相关问题,重点通常在三层:
- Key 本身是否设计合理
- 过期机制是否符合预期
- 内存淘汰策略是否和业务匹配
不要把“设置了 TTL”理解成“内存一定会立刻降下来”。
更进一步说:
- 过期解决的是生命周期
- 淘汰解决的是到达上限后的取舍
- 二者都不能替代合理的数据模型设计
一、为什么设置了过期也不代表立刻删除
Redis 的过期删除不是“到点立刻精确回收”的强实时机制。
常见理解可以分两种:
- 惰性删除:访问到这个 Key 时发现过期,再删除
- 定期删除:后台周期性抽样清理过期 Key
这意味着:
- 已经过期的 Key,短时间内仍可能存在内存中
所以“设置过期了为什么内存没立刻掉”并不奇怪。
尤其是在:
- 过期 key 很多
- 访问分布不均
- 实例负载较高
的情况下,这种体感会更明显。
二、真正该先关注的是什么
1. 有没有大 Key
即使都设置了过期,只要单个 Key 特别大,内存压力依然会很明显。
2. 有没有无上限增长结构
例如:
- 不断 append 的列表
- 不断膨胀的 Hash / Set / ZSet
3. 过期时间是不是设计得过于集中
大量 Key 在同一时刻过期,会放大波动。
4. 是否存在根本不该进 Redis 的数据
很多内存膨胀问题,本质不是 TTL 没配,而是把过多长尾、低价值、低命中数据也塞进缓存了。
三、内存淘汰策略为什么很关键
当 Redis 达到 maxmemory 上限后,是否还能继续写,取决于淘汰策略。
常见思路可以粗略理解为:
- 不淘汰,直接报错
- 优先淘汰设置了过期时间的 Key
- 淘汰最近最少使用或最不常用的 Key
- 在所有 Key 中做 LRU / LFU 类淘汰
最关键的不是记名字,而是想清楚:
- 你的 Redis 是纯缓存
- 还是还承载了必须保留的业务状态
这两个场景,淘汰策略往往不一样。
因为淘汰不是技术动作,而是业务取舍:
- 是宁可命中率下降
- 还是宁可写入失败
- 还是绝不能误删关键状态
四、为什么 TTL 集中过期很危险
如果一大批 key 都在相近时间过期,会同时带来几类问题:
- 命中率瞬间下滑
- 回源请求陡增
- 热点 key 重新构建带来抖动
所以更稳的做法通常是:
- TTL 加随机抖动
- 热点数据做分层缓存
- 重要缓存做预热或提前刷新
五、纯缓存场景更适合什么思路
如果 Redis 主要承载的是:
- 热点缓存
- 可丢失临时数据
那么更适合的往往是:
- 配合过期时间
- 再加适合的 LRU / LFU 类淘汰策略
因为这类数据本来就允许被替换。
六、如果 Redis 里放了关键状态怎么办
例如:
- 登录态
- 防重 token
- 分布式锁状态
这时就不能简单把它当“可随便淘汰的缓存”。
否则到了内存上限,问题会从“命中率下降”变成“业务逻辑异常”。
这类场景更应该先做的是:
- 隔离实例
- 严格容量规划
- 避免和纯缓存混用淘汰语义
七、排查内存问题时,信息要看成一组
真正排查时,最好把下面几类信息放一起看:
- used_memory 增长趋势
- key 数量增长趋势
- 大 key 分布
- TTL 分布
- evicted_keys
- hit / miss 变化
单看其中一个指标,很容易误判。
八、排查 Redis 内存问题更实用的顺序
第一步:先看内存增长速度
先判断是:
- 持续缓慢上涨
- 突然快速飙升
第二步:找大 Key 和热点结构
重点关注:
- 哪些业务 key 空间增长最快
- 哪类结构最容易膨胀
第三步:看 TTL 分布
确认:
- 是否很多 Key 没设置过期
- 是否 TTL 过于集中
第四步:看淘汰和命中情况
确认:
- 是否频繁触发淘汰
- 命中率是否下降明显
九、几个特别容易踩的坑
1. 把 Redis 当无限容量缓存
没有容量边界和淘汰策略,最终一定会出内存问题。
2. TTL 全部设置同一个值
这很容易造成一波集中失效。
3. 以为淘汰策略会“自动帮你兜住所有问题”
淘汰策略只能在内存满时做最后选择,不能替代合理的 Key 设计。
4. 关键状态和可丢缓存混用一套淘汰规则
这是线上非常常见、也非常危险的设计。
一句话总结
Redis 内存治理的关键,不是只盯着“有没有设置过期”,而是同时看:
- Key 设计
- 过期分布
- 大 Key 风险
- 淘汰策略与业务匹配度
当这几层都想清楚后,很多“Redis 怎么总是涨内存”的问题才会真正变得可控。