Redis 过期后内存未下降 怎样处理
来源:17golang原创
时间:2026-10-22 06:12:07 380浏览 收藏
我遇到过一种很容易误判的 Redis 内存告警:一批带 TTL 的缓存已经过期,业务读取也拿不到它们,但进程的 RSS 几乎没有下降。这个现象不一定说明过期失效,通常要把“键是否已经从逻辑数据集消失”“Redis allocator 是否复用了空闲块”“操作系统是否收回页面”拆开看。
官方地址:https://redis.io/
先给结论:先看 used_memory 是否下降,再看 used_memory_rss。前者下降、后者不变,多半是分配器碎片或峰值页面暂未归还;两者都不降,才继续排查过期清理、仍在增长的键和后台释放队列。
先把过期键和进程内存分开看
Redis 的过期不是“到点立刻让进程向操作系统归还同等大小内存”。键被访问时可以触发惰性清理,后台也会增量扫描过期键。即使键已经被删除,分配器仍可能保留页面,等待后续写入复用。
# 先看单个 key 的逻辑状态;-2 表示 key 不存在,-1 表示没有 TTL redis-cli TTL cache:item:42 redis-cli EXISTS cache:item:42 # 只读取内存字段,不用 KEYS 扫描生产实例 redis-cli INFO memory | egrep 'used_memory:|used_memory_rss:|allocator_frag_ratio:|allocator_resident:|lazyfree_pending_objects:'
如果 TTL 已经返回 -2,但 RSS 不动,先不要把问题定性为“Redis 没删”。如果业务使用的是集合、哈希字段或模块索引,也要确认你设置 TTL 的对象确实是顶层 key;字段级数据不能简单套用顶层 key 的判断。

用 INFO memory 判断到底是哪一层没下降
我通常先做一个很朴素的对比:used_memory 更接近 Redis allocator 已分配给数据和内部结构的用量,used_memory_rss 是操作系统看到的常驻页面。删除键后前者下降、后者维持高位,往往是 allocator 还握着可复用页面;这时 RSS 高不等于还有同样多的活跃键。
| 观察组合 | 优先判断 | 下一步 |
|---|---|---|
| used_memory 不降 | 键未按预期清掉,或新写入抵消了释放 | 抽查 TTL、写入量和 keyspace,确认是否持续生成新 key |
| used_memory 降,RSS 不降 | 分配器碎片、峰值页面或 RSS 额外开销 | 看 allocator_frag_ratio、allocator_resident,再选择整理动作 |
| lazyfree_pending_objects 持续升高 | 后台异步释放跟不上生产速度 | 先观察队列和 CPU,再决定是否调整大对象过期策略 |
这里不要只盯着 mem_fragmentation_ratio 一个比值。Redis 官方文档还提供 allocator_frag_ratio、allocator_frag_bytes、allocator_resident 等更细的分层指标;小幅差异或经历过很高峰值时,比值本身可能会放大感受。

按证据选择处理动作
如果只是 RSS 没下降,但 used_memory 已经回落,先让 allocator 复用这部分空间,不要为了一个高 RSS 立刻重启。若确认碎片长期偏高且 CPU 有余量,可以评估 active defragmentation;它是持续的 CPU 换内存整理,不是免费的“立即清空”。
# 先读取配置,确认实例是否支持并启用了主动碎片整理 redis-cli CONFIG GET activedefrag active-defrag-threshold-lower active-defrag-threshold-upper # 仅在确认 CPU 余量、变更已审批时启用;不要把它当作过期修复按钮 redis-cli CONFIG SET activedefrag yes # jemalloc 下尝试把可释放的脏页交还给 allocator;其他 allocator 可能是 NOOP redis-cli MEMORY PURGE
如果问题是大对象过期释放造成主线程抖动,可以评估 lazyfree-lazy-expire yes,但这会把释放转移到后台,短时间内要关注 lazyfree_pending_objects,它也不会保证 RSS 立刻下降。缓存场景还应设置合理的 maxmemory 和淘汰策略,按峰值、碎片和复制/AOF 等额外开销留出余量。
把排查动作沉淀成落地清单
我最后会把这件事收敛成四个固定动作:写入路径统一设置 TTL,并记录没有 TTL 的异常 key;监控同时采集 used_memory、used_memory_rss、allocator_frag_bytes 和 lazyfree_pending_objects;容量按峰值而不是某个平稳时刻估算;变更 active defrag、异步过期或 purge 前,先确认 CPU、复制、AOF 和回滚方案。
Redis 过期后“内存没下降”真正要回答的不是一个数字有没有马上变小,而是:数据是否已经释放、释放后的空间是否可复用、页面是否需要归还操作系统。按这个层次看,误报会少很多,真正的容量问题也更容易定位。
常见问题
TTL 到期后,为什么 DBSIZE 还可能暂时不变?
过期键会在访问时或后台增量清理时删除,TTL 到零与删除动作不是同一个瞬间。观察时要结合抽查结果和内存指标,不要只用一个瞬时数量下结论。
MEMORY PURGE 能不能直接解决内存泄漏?
不能。它处理的是 allocator 可以回收的页面,不能替代排查仍在增长的 key、没有 TTL 的数据或业务重复写入;而且该命令只在 jemalloc 下真正实现,执行也可能较慢。
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习