登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis 内存碎片率升高时怎么区分数据增长和分配器行为

来源:17golang原创

时间:2026-09-08 11:02:32 499浏览 收藏

Redis 的 mem_fragmentation_ratio 升高,并不等于当前数据量变大。先看 used_memoryused_memory_rss 的变化:前者跟着 Redis 当前分配的数据走,后者是进程驻留内存。删除过一批大键后,RSS 可能暂时留在高位;如果后续写入只复用了这些空闲块,RSS 不再上涨,原因更接近分配器行为,而不是数据持续增长。

要点速览
  • 先用 INFO memory 建立两个时间点的内存基线,不要只盯碎片率。
  • SCAN 分批遍历键名,再用 MEMORY USAGE 抽样定位业务前缀和大键。
  • 删除后 RSS 不降可能是分配器保留页;只有逻辑占用和业务写入都持续上升,才更像数据增长。

先把 Redis 的四个内存指标放在一起看

排查从两个时间点开始:记录业务低峰和高峰,或记录处理一批删除动作前后的值。下面的命令只读取信息,不会扫描键空间:

redis-cli INFO memory | egrep 'used_memory:|used_memory_rss:|mem_fragmentation_ratio:|allocator_allocated:|maxmemory:' # 先保存逻辑占用、RSS、分配器和上限
redis-cli INFO stats | egrep 'instantaneous_ops_per_sec:|expired_keys:|evicted_keys:' # 同时记录写入压力和淘汰背景

可以把结果按这张表理解。used_memory_rss / used_memory 是碎片率的重要基础,但它不是“浪费空间百分比”,也不能跨分配器、版本和工作负载直接套一个硬阈值。

观察项它回答什么常见判断
used_memoryRedis 当前数据及内部分配用了多少持续上升才支持“数据在增长”
used_memory_rss进程实际驻留了多少内存页删除后仍高,可能是分配器暂未归还
mem_fragmentation_ratioRSS 与逻辑占用的关系只能和时间序列及业务动作一起看
allocator_allocated分配器视角的已分配量帮助区分 Redis 计数与分配器状态

例如删除大量缓存后,used_memory 下降、RSS 基本不动,随后新写入时 RSS 也保持平稳,这一组证据更符合“空闲块被复用”。反过来,两个指标都随键数量和写入量同步上升,才应优先查业务是否扩大了缓存范围、TTL 是否失效或 value 是否变大。

Redis used_memory、used_memory_rss、分配器空闲块与碎片率的关系边界
图1:Redis 的当前数据占用与进程 RSS 不是同一个量,碎片率只是二者关系的观测结果。

用 SCAN 和 MEMORY USAGE 找到真正变大的键

总量只能告诉你“哪里不对”,不能告诉你“谁变大了”。生产实例不要用 KEYS * 一次性阻塞遍历,而是用小批量 SCAN,配合 TYPEMEMORY USAGETTL 做抽样:

redis-cli --scan --pattern 'session:*' | head -n 100 | while IFS= read -r key; do
  type=$(redis-cli TYPE "$key") # 先确认数据类型,避免按错结构处理
  bytes=$(redis-cli MEMORY USAGE "$key" SAMPLES 5) # 用固定抽样近似单键占用,避免递归遍历全部元素
  ttl=$(redis-cli TTL "$key") # 记录过期边界,判断增长是否来自长期不失效
  printf '%s\t%s\t%s\t%s\n' "$bytes" "$ttl" "$type" "$key"
done | sort -nr | head -n 20 # 先看抽样中的大键候选

这个示例只取前 100 个键,适合先确认命令和字段;正式排查应让游标完整走完,或按业务前缀分批运行并汇总。MEMORY USAGE 返回的是单键近似占用,SAMPLES 对嵌套类型影响精度;它适合排序和定位,不应被当作精确账单。

如果某个前缀的键数量明显增加,且大键候选没有变化,问题更可能是键数量或 TTL 变化;如果键数量稳定但少数 Hash、List、Set 或 ZSet 的占用持续上升,应检查集合是否没有上限、是否把过多字段塞进一个键,或是否误把明细数据放进缓存。

Redis SCAN、TYPE、MEMORY USAGE、TTL 到业务前缀和大键候选的静态证据链
图2:SCAN 负责渐进遍历,MEMORY USAGE 负责单键近似占用,二者结合才能定位业务前缀和大键。

把碎片率、写入和删除时间对照起来

建议把每次采样保存成同一张表,而不是只在告警时看一次:

组合现象更可能的原因下一步
used_memory、RSS 都涨数据量、value 或集合规模增长按前缀和大键候选定位写入来源
used_memory 降、RSS 高位不动删除后分配器保留已申请页面观察后续写入是否复用 RSS,按峰值规划容量
键数量稳定、单键占用涨集合字段或元素持续膨胀检查写入边界、拆分结构和 TTL
碎片率高但逻辑占用很低历史峰值拉高了 RSS不要只按比例扩容,保留绝对值和时间序列

修复动作要跟证据匹配:数据真的增长时限制 TTL、控制集合大小或缩小缓存范围;只是 RSS 暂高时先观察分配器复用和峰值内存;单键膨胀时拆分结构或给写入设置上限。直接重启 Redis 可能让 RSS 下降,却会掩盖增长来源,也会引入持久化、故障切换和冷缓存成本。

常见问题

碎片率超过某个数值就必须重启吗?

不能只按一个数值决定。要同时看 used_memory、RSS、绝对内存余量、业务峰值和后续写入是否复用空闲块。

删除键后 RSS 为什么不马上下降?

底层分配器可能保留页面,供后续分配复用;这并不等同于 Redis 仍然持有同样的数据。容量规划应按历史峰值留余量。

MEMORY USAGE 能统计整个 Redis 的精确内存吗?

它用于查询单个键的近似占用,嵌套结构还会受 SAMPLES 影响。全局判断要结合 INFO memory 和分批扫描汇总。

参考资料

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>