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

Redis 大键怎么用 MEMORY USAGE 和抽样扫描定位

来源:17golang原创

时间:2026-09-08 09:48:45 288浏览 收藏

Redis 出现内存上涨时,先不要直接执行 KEYS * 或凭键名猜“大键”。更稳妥的做法是:用 SCAN 按游标分批枚举目标命名空间,再对候选键调用 MEMORY USAGE 比较字节数;只有进入候选集的聚合类型,才考虑提高 SAMPLES 精度。这样既能定位单键占用,也不会把单键问题和实例碎片率混为一谈。

要点速览
  • SCANCOUNT 只是工作量提示,游标返回 0 才代表一轮遍历结束,结果可能包含重复键。
  • MEMORY USAGE 统计键、值和管理开销;聚合类型默认抽样 5 个嵌套元素,SAMPLES 0 才会采样全部。
  • 发现大键后先确认数据类型、元素数量和访问模型,再决定拆分、限长或清理,不能只看一个字节数就删除。

先用 SCAN 找到值得测量的候选键

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type] 是增量式键空间迭代。第一次把游标设为 0,之后持续使用 Redis 返回的新游标,直到再次得到 0MATCH 适合限定业务前缀,TYPE 可以缩小到某种数据类型,COUNT 只影响每次调用的工作量提示,并不保证返回固定数量。

参数作用排查时的判断
cursor保存迭代位置返回 0 才完成一轮
MATCH按 glob 模式筛选键名优先限制业务前缀
COUNT每次调用的工作量提示不是固定返回条数
TYPE按 Redis 数据类型过滤缩小候选范围,不代表内存大小

下面的命令只演示“收集候选键”,没有把结果当成大键结论。生产排查应选择低峰窗口,并把前缀换成真实业务命名空间:

# 中文注释:只扫描订单缓存命名空间,不使用会阻塞全库的 KEYS
redis-cli --scan --pattern 'order-cache:*' --count 100

# 中文注释:按游标逐批读取某个类型,直到返回游标为 0
redis-cli SCAN 0 MATCH 'order-cache:*' COUNT 100 TYPE hash

不要因为某一批返回空数组就停止;只要游标不是 0,迭代就没有完成。键在扫描期间发生新增、删除或迁移时,完整遍历也不等价于某一时刻的严格快照;同一个键可能出现多次,所以后续统计要允许去重。

Redis SCAN 将命名空间、游标、匹配模式和类型过滤组织成候选键集合的静态关系图
图1:SCAN 只负责把命名空间收敛为候选键集合,游标、匹配模式和类型过滤属于扫描边界。

用 MEMORY USAGE 判断单键到底占了多少内存

拿到候选键后,使用 MEMORY USAGE key 读取 Redis 为该键和值分配的内存字节数,其中也包含数据结构管理开销。它回答的是“这个键在 Redis 内存里大约占多少”,不是业务字段长度,也不是整个实例的 RSS。

# 中文注释:先测单键,便于和同一命名空间的其他键比较
redis-cli MEMORY USAGE 'order-cache:20260908:001'

# 中文注释:对候选键输出类型、元素数量和估算字节数
key='order-cache:20260908:001'
printf 'key=%s type=%s items=%s bytes=%s\n' "$key" \
  "$(redis-cli TYPE "$key")" \
  "$(redis-cli HLEN "$key" 2>/dev/null || true)" \
  "$(redis-cli MEMORY USAGE "$key")"

对于 string,长度和编码通常足以帮助解释结果;对于 hash、list、set、zset 等聚合类型,默认 SAMPLES 5 是估算路径,不应把它误读成“只统计了五个元素”。如果只需要先排序找候选,默认值通常更合适,因为每次测量的工作量更低。

Redis MEMORY USAGE、SAMPLES 5、SAMPLES 0 与实例碎片率的内存归因边界图
图2:MEMORY USAGE 观察单键与值的占用,SAMPLES 控制聚合类型的估算范围,实例碎片率应单独观察。

只对候选大键增加抽样精度

当某个 hash 或 zset 明显高于同类键,再用 SAMPLES 0 做复核,表示采样全部嵌套元素。它的复杂度随采样数量增长,不适合对整个键空间里的每个聚合键无差别调用:

# 中文注释:只对已入选的聚合键读取更完整的内存估算
key='order-cache:20260908:001'
type=$(redis-cli TYPE "$key")
bytes=$(redis-cli MEMORY USAGE "$key" SAMPLES 0)
printf 'candidate=%s type=%s bytes=%s\n' "$key" "$type" "$bytes"

# 中文注释:用类型专属命令确认膨胀来自元素数量还是单个值过大
redis-cli HLEN "$key"  # 中文注释:hash 关注字段数量
redis-cli MEMORY USAGE "$key" SAMPLES 0

“大”没有脱离业务的统一阈值:一个低频 hash 可能值得拆分,一个高频小 hash 也可能因访问路径不当拖慢请求。建议把结果和同前缀键的分位数、访问频率、TTL、元素数量一起记录,再决定是否拆分对象、限制列表长度或调整缓存粒度。

把大键、碎片率和处理动作分开判断

单键占用高,说明数据模型或某个值可能膨胀;实例的 mem_fragmentation_ratio 偏高,则说明分配器与进程常驻内存之间存在额外空间,二者不是同一证据。可以补看:

# 中文注释:读取实例级内存指标,和单键 MEMORY USAGE 分开记录
redis-cli INFO memory | grep -E 'used_memory:|used_memory_rss:|mem_fragmentation_ratio:'

如果大键集中在同一种业务对象,优先从写入侧限制字段数、单值长度或集合增长速度;如果单键并不突出但碎片率持续异常,再独立评估分配器、重启窗口和实例容量。任何删除或拆分动作都要先确认 TTL、回源能力和并发读写模型,先灰度一个前缀比一次性清空更可控。

常见问题

SCAN 能不能完全替代 KEYS?

在生产排查键空间时通常应优先用 SCAN,因为它分批返回、单次调用成本更可控;但它不是严格快照,仍需处理重复键和扫描期间的键变化。

MEMORY USAGE 为什么和字符串长度不一样?

它统计的是 Redis 在内存中的分配,除了值本身还包括键、编码和管理开销;短字符串也可能有明显的固定开销。

SAMPLES 0 是不是越精确越应该默认使用?

不是。SAMPLES 0 会扩大聚合类型的测量工作量,适合对少量候选大键复核;全库粗筛先用默认抽样,再针对候选加精度更稳妥。

需要查参数细节时,可直接参考 Redis 官方的 SCAN 命令文档MEMORY USAGE 命令文档,再按目标实例版本和客户端实现调整命令。

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