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

Redis MEMORY USAGE 与逻辑数据大小有何区别

来源:17golang原创

时间:2026-11-14 20:16:32 126浏览 收藏

Redis 的“逻辑数据大小”和“占用多少内存”不是同一个数字。字符串的业务内容可能只有 3 个字节,但 Redis 还要保存键名、对象元数据、分配器块以及数据结构本身的管理信息。MEMORY USAGE key 返回的是这个键和值在 Redis RAM 中的估算占用,因此它通常大于 STRLEN 返回的字符串长度;对 Hash、List、Set 等聚合类型,还会受到内部编码和采样策略影响。

官方地址:https://redis.io/

要点速览
  • 逻辑大小描述业务内容,MEMORY USAGE 描述单个键和值的 RAM 分配估算。
  • 结果包含数据与管理开销;小对象也可能因为固定开销显示几十字节。
  • 嵌套数据类型默认只采样 5 个成员,需要完整估算时使用 SAMPLES 0,但成本会随成员数量增加。
  • 它适合找热点键,不能代替 INFO memory 或 MEMORY STATS 做实例级容量判断。

先把三个“大小”分开

排查 Redis 内存时,最容易把三个层次混在一起:

指标回答的问题典型工具
逻辑数据大小业务内容有多少字节、字段或成员STRLEN、HLEN、应用侧序列化长度
单键内存占用这个键和值在 Redis 内存中大约占多少MEMORY USAGE key
实例总内存Redis 进程和内部组件总体分配了多少内存INFO memory、MEMORY STATS

例如,字符串值是 bar 时,业务内容只有 3 个字节;但单键结果还要覆盖键名、Redis 对象和分配器相关开销。反过来,多个小键的单键结果相加,也不能简单等同于进程 RSS,因为实例还可能有客户端缓冲区、复制积压、AOF 缓冲区、数据库字典和内存碎片。

Redis MEMORY USAGE 将逻辑数据、单键内存和实例总内存分成三层的结构说明图
图1:结构说明图,查看逻辑数据、单键 RAM 估算与实例级内存指标之间的静态关系。

MEMORY USAGE 返回的到底是什么

Redis 官方对命令的定义是:返回一个键及其值存储在 RAM 中所需的字节数,并且这个数字包含数据分配和管理开销。键不存在时返回空值,而不是返回 0。命令自 Redis 4.0.0 起提供,基本形式如下:

# 查询单个键和值的 RAM 占用估算,返回整数或不存在时的空值
redis-cli MEMORY USAGE user:1001

# 先判断键是否存在,避免把空值误写成“占用 0 字节”
redis-cli EXISTS user:1001

# 查询字符串的逻辑字节长度,用来和单键内存估算做层次对照
redis-cli STRLEN user:1001

这里不要把返回值理解成“值的长度”。同一个字符串值换一个更长的键名,结果可能改变;同样长度的两个值,使用不同数据类型或不同内部编码,结果也可能不同。Redis 文档中的空字符串示例也说明,即使没有实际业务内容,空键和值仍可能有固定的内部开销。

因此,MEMORY USAGE 更适合回答“这个键在 Redis 里大约占多少 RAM”,而不是“用户提交了多少字符”。

聚合类型为什么要关注 SAMPLES

Hash、List、Set、Sorted Set 等类型包含多个嵌套值。对这类对象,命令可以通过 SAMPLES count 指定抽样成员数量。默认值是 5,SAMPLES 0 表示抽取全部嵌套值来估算总大小:

# 默认采样 5 个嵌套值,适合先扫一批键做低成本定位
redis-cli MEMORY USAGE cart:1001

# 显式采样 20 个成员,减少极端成员对小样本估算的影响
redis-cli MEMORY USAGE cart:1001 SAMPLES 20

# 采样全部成员,适合复核单个热点对象,但成本随成员数增加
redis-cli MEMORY USAGE cart:1001 SAMPLES 0

采样不是“把结果除以成员数再乘回去”这么简单的业务层计算,而是 Redis 对嵌套数据的估算方式。成员大小比较均匀时,默认采样通常足够做热点筛选;如果一个 Hash 同时包含大量短字段和少量超长字段,或者你正在复核一个容量异常对象,应提高样本数,必要时对该对象使用 SAMPLES 0。

命令的时间复杂度按样本数计算,因此不要在生产高峰对大量超大聚合对象逐个执行全量采样。更稳妥的做法是先用默认采样找候选,再对少量候选复核。

Redis MEMORY USAGE 对嵌套数据采样并受到内部编码影响的关系说明图
图2:关系说明图,查看嵌套成员、SAMPLES 采样范围、内部编码与最终内存估算之间的静态关系。

键名、管理开销和内部编码都会改变结果

把差异拆开看,通常有三个来源。

键和值之外,还有对象管理开销

Redis 需要维护键空间、过期信息以及数据对象本身。对于非常小的 String,固定开销占比会很明显,所以“内容只有几个字节”并不意味着“只占几个字节”。键名越长,逻辑内容不变时,单键估算也可能跟着增长。

小型聚合对象可能使用紧凑编码

Redis 的内存优化文档说明,小型 Hash、List、整数集合和 Sorted Set 可以使用更紧凑的内部编码;当元素数量或元素大小超过配置阈值时,Redis 可能转换到普通编码。这个转换对调用方通常是透明的,但会改变对象的内存常数。

# 查看影响紧凑编码阈值的配置,实际名称随 Redis 版本而变
redis-cli CONFIG GET hash-max-listpack-entries
redis-cli CONFIG GET hash-max-listpack-value

# 对比同一个对象在扩容前后的估算,先记录结果再改变数据
redis-cli MEMORY USAGE profile:1001 SAMPLES 0

不要把某一次测试中的“每个成员平均多少字节”当成永久公式。Redis 版本、编译位数、分配器、键名长度、成员分布和编码阈值都会影响结果。

单键估算仍不是进程 RSS

删除键后,底层分配器未必立即把所有页面归还给操作系统;复制、客户端、AOF 和数据库内部结构也不属于某个业务键的单键结果。因此,出现“所有热点键看起来不大,但 Redis 进程仍很大”时,应转向 INFO memory 或 MEMORY STATS 查看实例级指标和分配器状态。

把 MEMORY USAGE 用成热点键排查工具

一个实用的排查顺序是:先用业务前缀或抽样扫描找候选键,再读取单键估算;发现聚合类型异常后提高 SAMPLES;最后把单键结果和实例级内存指标放在同一张表里解释。不要把命令结果直接当作“可释放内存”,也不要看到结果变大就立刻修改编码阈值。

# 先取实例级已分配内存,作为单键分析的背景指标
redis-cli INFO memory | grep '^used_memory:'

# 对已知候选键分别观察单键估算,避免一次全库全量扫描
redis-cli MEMORY USAGE session:1001 SAMPLES 20
redis-cli MEMORY USAGE cart:1001 SAMPLES 0

# 查看各类实例开销,判断差额是否来自业务键之外
redis-cli MEMORY STATS

如果目标是容量规划,应按峰值数据量、复制和持久化过程中的额外开销、分配器碎片以及客户端缓冲区预留空间。MEMORY USAGE 提供的是“对象级证据”,它能帮你定位谁最占空间,却不能单独给出实例应该设置多大的 maxmemory。

常见问题

MEMORY USAGE 返回 0 代表键不存在吗?

不是。键不存在通常返回空值;返回整数 0 也不应被当作通用的“不存在”判断,业务代码应先用返回类型或 EXISTS 区分。

为什么 STRLEN 很小,MEMORY USAGE 却更大?

STRLEN 只描述字符串内容的逻辑字节长度,MEMORY USAGE 还包含键名、Redis 对象、分配器和管理开销。

SAMPLES 0 是不是任何时候都更准确?

它会遍历全部嵌套成员,适合少量对象复核;对大对象或批量扫描,默认采样或有限样本更适合控制命令成本。

能不能把所有键的 MEMORY USAGE 相加当作 used_memory?

不能。实例级内存还包括数据库字典、客户端、复制、AOF、内部结构和碎片等非单键开销。

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