Redis MEMORY STATS 如何查看内存详细统计?

来源:PostgreSQL教程作者:澳门程序员头衔:程序员
导读:本期聚焦于澳门程序员创作的《Redis MEMORY STATS 如何查看内存详细统计?》,敬请观看详情。排查 Redis 内存占用时,只看 INFO memory 里的 used_memory 往往只能得到总量,无法判断内存具体消耗在哪些地方。MEMORY STATS 命令可以返回更细粒度的内存统计信息,覆盖分配器状态、数据集占用、Lua 脚本缓存、客户端输出缓冲区以及复制积压等多个维度。本文结合 redis-cli 的实际输出,逐项解释 allocator_allocated、allocator_active、used_memory_dataset、overhead.total 等核心字段,说明如何根据这些数据计算内存碎片率。同时对比 MEMORY STATS 与 INFO memory 的同名指标,梳理字段映射关系,帮助你在排查内存偏高、大 key、脚本缓存等问题时快速定位消耗点,避免仅凭总量指标误判。

在排查 Redis 内存占用问题时,很多同学习惯直接执行 INFO memory,然后盯着 used_memory 看。这个方法能知道当前进程用了多少内存,但一旦遇到内存异常增长、内存碎片偏高或者实例实际占用比预想大很多,单看总量指标往往很难找到原因。Redis 从 4.0 开始提供了 MEMORY STATS 命令,它把内存统计拆得更细,可以看到分配器内部状态、数据集真实大小、管理开销、Lua 脚本缓存等不同维度的占用情况。这篇文章就围绕 MEMORY STATS 展开,说明它的输出结构、关键指标含义,以及如何用它配合 INFO memory 做内存分析。

Redis MEMORY STATS 如何查看内存详细统计?

MEMORY STATS 命令基础与输出结构

在 redis-cli 中直接执行 MEMORY STATS,会得到一组类似 JSON 结构的数据。这个命令不需要额外参数,返回信息比 INFO memory 更偏向内存分配器的视角。比如一个简单实例的输出片段如下:

127.0.0.1:6379> MEMORY STATS
 1) "peak.allocated"
 2) (integer) 1048576
 3) "total.allocated"
 4) (integer) 524288
 5) "startup.allocated"
 6) (integer) 897712
 7) "replication.backlog"
 8) (integer) 1048576
 9) "clients.slaves"
10) (integer) 0
11) "clients.normal"
12) (integer) 49616
13) "aof.buffer"
14) (integer) 0
15) "lua.caches"
16) (integer) 0
17) "overhead.total"
18) (integer) 1995904
19) "keys.count"
20) (integer) 1
21) "keys.bytes-per-key"
22) (integer) 87381
23) "dataset.bytes"
24) (integer) 87381
25) "dataset.percentage"
26) (float) 4.19
27) "peak.percentage"
28) (float) 50
29) "allocator.allocated"
30) (integer) 542997
31) "allocator.active"
32) (integer) 1048576
33) "allocator.resident"
34) (integer) 1048576
35) "fragmentation"
36) (float) 1.93
37) "fragmentation.bytes"
38) (integer) 505579

这里只截取了一部分字段,但已经能看出 MEMORY STATS 把内存拆成了几个组:以 peak、total、startup、replication.backlog、clients、lua.caches、aof.buffer 开头的指标,描述的是 Redis 内部各模块占用的内存;而 allocator 系列指标,描述的是底层内存分配器,例如 jemalloc 或 libc malloc 的状态;dataset 系列则专门描述用户键值数据占用的内存。

理解这种分组关系很重要。比如 total.allocated 是 Redis 认为自己已经分配出去的内存,它与 allocator.allocated 并不完全相同,因为分配器自身有对齐、元数据以及碎片等额外开销。因此在分析时不能只盯某一个字段,而要结合 allocator 与 dataset 一起看。

核心字段解读:分配器、碎片与数据集

先看分配器相关的几个指标。以 jemalloc 为例,allocator.allocated 表示 Redis 通过分配器申请到的、正在使用中的内存字节数,allocator.active 是分配器为了满足这些请求实际保留的活跃内存页大小,而 allocator.resident 是分配器在操作系统层面实际驻留的物理内存。一般来说,allocator.active 会大于或者等于 allocator.allocated,因为分配器不可能每次申请都刚好用完一整页。

碎片率主要看 fragmentation 和 fragmentation.bytes。在 INFO memory 中也有 mem_fragmentation_ratio,它的计算方式是 used_memory_rss / used_memory。而 MEMORY STATS 中的 fragmentation 则是从分配器内部视角计算出来的,通常由 allocator.active / allocator.allocated 得到。如果一个实例的 fragmentation 持续高于 1.5,同时 fragmentation.bytes 数值也很大,说明分配器内部存在较多浪费,可能需要考虑启用 jemalloc 的主动碎片整理,或者重启实例来回收内存。

数据集相关的 dataset.bytes 表示用户数据实际占用的内存,也就是所有键和值经过序列化之后的总大小。keys.count 是当前键的总数,keys.bytes-per-key 是平均每个键分摊到的内存字节数,这个值在对比不同业务 Redis 实例时比较有用。dataset.percentage 表示数据集占 total.allocated 的百分比。如果这个比例较低,说明大量内存没有被用户数据使用,而是被复制积压、客户端缓冲区、脚本缓存或者其他管理开销占用了。

还有一个容易被忽略的指标是 overhead.total,它汇总了 Redis 为了维护键值数据之外的功能所消耗的内存,包含复制积压缓冲区、客户端输出缓冲区、AOF 缓冲区、Lua 脚本缓存等等。在大 key 很多或者主从复制频繁的场景下,overhead.total 可能比 dataset.bytes 还要高,这时只清理数据并不能显著降低内存占用,反而需要检查客户端连接、复制状态和脚本使用情况。

MEMORY STATS 与 INFO memory 的字段对比

很多 Redis 用户对 INFO memory 里的字段更熟悉,例如 used_memory、used_memory_human、used_memory_rss、used_memory_peak、used_memory_lua、mem_fragmentation_ratio 等。MEMORY STATS 并不是要替代 INFO memory,而是从另一个角度补充更细的信息。理解两者的对应关系,可以更快定位内存问题。

比如 used_memory 对应的是 total.allocated,表示 Redis 内部统计的所有已分配内存总量。used_memory_rss 对应 allocator.resident 的一部分,不过 rss 还包括进程其他内存段,所以两者不完全等价。used_memory_peak 对应 peak.allocated,used_memory_lua 在较新版本中对应 lua.caches。当你在 INFO memory 里看到 used_memory 很高,但业务数据量没有增加时,可以马上执行 MEMORY STATS,重点看 overhead.total 下各个子项,找到是复制积压、客户端还是脚本导致的内存占用。

另一个典型的场景是主从复制。主节点会为每个从节点维护一个复制积压缓冲区,默认大小由 repl-backlog-size 控制。这个大小不会因为从节点消费慢而自动缩小,所以从节点很多或者网络抖动频繁时,replication.backlog 可能会占用大量内存。通过 MEMORY STATS 可以看到这一项的具体字节数,再结合 INFO replication 查看从节点数量和积压情况,就能判断是否需要调整 repl-backlog-size 参数。

用 MEMORY STATS 排查内存问题的实践思路

假设线上一个 Redis 实例的总内存持续逼近 maxmemory,但键数量并没有明显增长。常规思路是先执行 INFO memory,如果发现 used_memory 明显小于 used_memory_rss,说明碎片较高;如果两者接近,但 used_memory 仍然很大,就需要进一步拆分内部占用。这时可以执行 MEMORY STATS,按照以下顺序检查。

第一步看 dataset.bytes 和 overhead.total。如果 dataset.bytes 占比很高,说明内存主要花在业务数据上,下一步需要使用 redis-cli --bigkeys 或者 MEMORY USAGE key 找出大 key。如果 overhead.total 占比很高,则继续查看 clients.normal、clients.slaves、replication.backlog、lua.caches 等子项,定位具体原因。

第二步看 fragmentation 和 allocator.active。如果碎片率超过 1.5,尤其是达到 2 以上,并且 fragmentation.bytes 占据了几百 MB 甚至更多,说明分配器内部浪费严重。此时可以考虑把 activedefrag 参数打开,让 Redis 在后台自动整理碎片。当然,启用主动碎片整理会消耗一定的 CPU,需要在内存和 CPU 之间权衡。

第三步结合 peak.allocated 和 peak.percentage 判断内存峰值是否合理。如果当前内存只有峰值的 50%,但实例仍然被限制在最大内存附近,可能是某些已经释放的内存没有真正归还给操作系统,或者 maxmemory-policy 触发过淘汰后又重新写入。这类问题需要结合业务写入模式和 key 过期策略一起分析,单看瞬时统计无法得出结论。

此外,如果使用了 Lua 脚本,并且脚本执行过程中会向 Redis 写入数据,那么 lua.caches 可能会慢慢增长。通过 MEMORY STATS 能直接看到 Lua 脚本缓存占用的字节数,再执行 SCRIPT FLUSH 可以清空脚本缓存,但要注意线上环境需要确认脚本调用方是否会自动重新加载。

实战示例:计算内部各模块内存占比

下面给出一段简单的 shell 命令,用来把 MEMORY STATS 中几个关键字段提取出来,方便观察内存分布在哪些模块。

redis-cli MEMORY STATS | grep -E "dataset.bytes|overhead.total|replication.backlog|clients.normal|lua.caches|fragmentation$|allocator.allocated|allocator.active"

在实际定位问题时,如果输出类似下面这样:

1) "dataset.bytes"
2) (integer) 104857600
3) "overhead.total"
4) (integer) 52428800
5) "replication.backlog"
6) (integer) 16777216
7) "clients.normal"
8) (integer) 2097152
9) "lua.caches"
10) (integer) 1048576
11) "fragmentation"
12) (float) 1.12
13) "allocator.allocated"
14) (integer) 157286400
15) "allocator.active"
16) (integer) 176160768

从这些数据可以看出,数据集占据 100 MB,管理开销约 50 MB,其中复制积压约 16 MB,客户端普通连接约 2 MB,Lua 缓存约 1 MB。碎片率只有 1.12,说明碎片问题不大,内存压力主要来自数据本身和复制积压。此时可以优先检查是否存在大 key 或长期未过期的数据,同时评估 repl-backlog-size 是否需要调小。

如果换成另一种情况,dataset.bytes 只有 20 MB,但 overhead.total 高达 150 MB,并且 clients.normal 也接近 100 MB,那就要怀疑是否存在大量普通客户端长期订阅通道或者输出缓冲区积压。比如某个消费者处理速度很慢,导致 Redis 为该客户端分配的输出缓冲区不断增长,最终拖垮整个实例。此时通过 CLIENT LIST 查看 omem 字段,可以找到占用内存最大的客户端连接。

需要注意的是,MEMORY STATS 的输出在不同 Redis 版本中字段会略有差异,比如 Redis 7 之后增加了 functions.caches 和 aof.buffer 等更细的字段。因此分析时最好结合当前版本的 INFO memory 和官方文档,不要机械套用旧版本字段映射。

小结

MEMORY STATS 是 Redis 内存分析中一个非常实用的命令。它把内存从分配器、数据集、复制积压、客户端、Lua 缓存等维度拆开,弥补了 INFO memory 只有总量指标的不足。在排查内存占用高、碎片率高、主从复制内存异常等场景时,先看 dataset.bytes 和 overhead.total 确定大方向,再看 fragmentation 和各个子模块,可以快速缩小问题范围。配合 MEMORY USAGE、MEMORY DOCTOR 以及 CLIENT LIST 等命令,能够更全面地掌握 Redis 实例的内存健康状况,避免盲目扩容或重启。

Redis内存统计MEMORY STATS内存碎片率修改时间:2026-10-04 00:14:24

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1004/65309.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。