Redis内存到底咋用的,进程占用差异和实际表现聊聊
- 问答
- 2025-12-27 12:31:04
- 1
关于Redis内存到底咋用的,以及我们平时看到的服务器进程占用内存和Redis自己报告的内存为什么总对不上,这事儿确实挺让人困惑的,咱们就聊聊这个,尽量说大白话。
第一部分:Redis的内存主要花在哪儿了?
Redis就像一个超级快的“内存大仓库”,所有数据都放在内存里,所以它的内存消耗是核心问题,它的内存主要用在以下几个地方:
-
你的数据本身: 这是最大头的一部分,就是你用SET、HSET、LPUSH这些命令存进去的键值对,比如你存了一个字符串“hello world”,或者一个包含一百万个元素的列表,这些数据本身就要占地方,这部分是实实在在的有效内存使用。
-
管理数据产生的“额外开销”: 这是关键所在,Redis为了能飞快地找到和管理你的数据,会给每个键值对都配上一些“管理信息”,这就像图书馆里每本书除了书本身的内容(你的数据),还需要一个书号、一个索引卡(管理开销)来帮你快速定位,根据(Redis官方文档)的说法,这些开销可不小。
- 每个键值对(无论值多大)都会有一个叫
redisObject的结构体来记录这个值的类型、编码方式、引用计数等。 - 键名(key)本身也是需要存储的,比如你有一个键叫
user:1000:profile,这个长字符串也得占内存。 - 对于复杂数据类型如哈希、列表、集合,Redis内部用不同的数据结构(比如字典、跳跃表)来组织,这些数据结构本身也有节点指针、长度记录等开销。(来自Redis源码分析)表明,有时候这些额外开销甚至能和存储的数据本身一样大,尤其是当你的键很多,但每个键对应的值都很小(比如只存一个数字)的时候,开销占比会非常惊人。
- 每个键值对(无论值多大)都会有一个叫
-
“内存碎片”: 想象一下你的内存是一大张空白格子纸,你不停地写入和删除不同大小的数据,就像在纸上不停地写不同长度的句子又擦掉,时间长了,纸上会留下很多零零散散的空隙,这些空隙可能每个都不大,单独放不下新数据,但加起来总量很可观,这就是内存碎片,Redis虽然有自己的内存分配器来尽量减少碎片,但无法完全避免,当频繁修改不同大小的数据时,碎片就会变多。
-
其他零碎开销: 比如Redis服务器运行本身需要一点内存,客户端的连接缓冲区(存放要发给客户端的数据)等,但这些通常占比较小。
第二部分:进程占用差异和实际表现
现在我们来看最核心的问题:为什么在服务器上用top或ps命令看到的Redis进程占用的内存(常称为RSS,常驻内存集),总是比用Redis的INFO memory命令查到的used_memory要大不少?
简单来说就是:used_memory是Redis认为自己“真正用了”的内存(主要是第1、2部分),而进程的RSS是操作系统看到的“这个程序占了我多少物理内存”(包含了第1、2、3、4部分,尤其是碎片和内存分配器的行为)。
具体聊聊差异的来源:
-
内存碎片是头号“嫌犯”: 这是导致差异最常见的原因,上面提到的那些被浪费的“空隙”,Redis在
used_memory计算中是不把它们算作已用内存的,因为它们确实没存有效数据,但这些空隙仍然被Redis进程占用着,操作系统可不管你是不是碎片,只要划给你了,就算在你的RSS里,Redis的INFO memory命令里有个mem_fragmentation_ratio(内存碎片率)指标,它就是 RSS / used_memory 的比值,如果这个值远大于1(比如大于1.5),就说明碎片很严重了。 -
操作系统的“延迟释放”: 当Redis删除数据释放内存时,操作系统为了性能考虑,不一定立刻就把这块物理内存收回来,可能还让它留在进程的RSS里,等系统内存紧张时再回收,所以你会看到数据删了,
used_memory下降了,但RSS可能一时半会儿没变。 -
Redis自身的内存分配器: Redis不是每次都直接向操作系统要一点点内存,它会先申请一大块内存(比如1MB),然后从这一大块里切出小部分满足你的数据存储需求,这一大块预分配的内存,只要还没用完,即使里面有部分空闲,也会整个算在RSS里,这也会导致
used_memory小于RSS。
实际表现和怎么办?
- 正常情况: 碎片率在1到1.5之间通常是可以接受的,属于正常表现。
- 碎片率过高: 如果碎片率持续很高,意味着你虽然实际数据没那么多,但进程却占着大量用不上的内存,浪费资源,可以考虑:
- 重启Redis:这是最直接有效的方法,但会有服务中断。
- 使用Redis 4.0以上版本的
MEMORY PURGE命令(前提是用了jemalloc分配器)来尝试主动释放碎片。 - 检查是否是因为频繁修改不同大小Key导致的,优化一下数据设计和写入模式。
- 碎片率小于1: 这种情况比较少见,但可能发生,这通常意味着操作系统发生了“交换”(Swap),也就是物理内存不够了,操作系统把Redis进程部分不常用的内存数据挪到了硬盘上。这是非常危险的信号! 因为Redis的性能基石就是全部数据在内存中,一旦发生交换,速度会急剧下降,这时候你需要赶紧给服务器加内存,或者减少Redis的数据量。
总结一下:Redis报告的内存是它认为有用的内存,而进程占用的内存是操作系统视角下实实在在划出去的全部内存,中间差着内存碎片、预分配策略和操作系统的延迟回收等。 平时监控时,既要看used_memory了解数据量增长,也要关注内存碎片率,避免不必要的浪费和性能问题。

本文由符海莹于2025-12-27发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://www.haoid.cn/wenda/69408.html
