news 2026/7/2 4:51:59

深入学习Redis(1):Redis内存模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入学习Redis(1):Redis内存模型

Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并发不可或缺的一部分。

我们使用Redis时,会接触Redis的5种对象类型(字符串、哈希、列表、集合、有序集合),丰富的类型是Redis相对于Memcached等的一大优势。在了解Redis的5种对象类型的用法和特点的基础上,进一步了解Redis的内存模型,对Redis的使用有很大帮助,例如:

1、估算Redis内存使用量。目前为止,内存的使用成本仍然相对较高,使用内存不能无所顾忌;根据需求合理的评估Redis的内存使用量,选择合适的机器配置,可以在满足需求的情况下节约成本。

2、优化内存占用。了解Redis内存模型可以选择更合适的数据类型和编码,更好的利用Redis内存。

3、分析解决问题。当Redis出现阻塞、内存占用等问题时,尽快发现导致问题的原因,便于分析解决问题。

这篇文章主要介绍Redis的内存模型(以3.0为例),包括Redis占用内存的情况及如何查询、不同的对象类型在内存中的编码方式、内存分配器(jemalloc)、简单动态字符串(SDS)、RedisObject等;然后在此基础上介绍几个Redis内存模型的应用。

在后面的文章中,会陆续介绍关于Redis高可用的内容,包括主从复制、哨兵、集群等等,欢迎关注。

系列文章

深入学习Redis(1):Redis内存模型

深入学习Redis(2):持久化

深入学习Redis(3):主从复制

深入学习Redis(4):哨兵

深入学习Redis(5):集群

目录

一、Redis内存统计

二、Redis内存划分

1、数据(或者称为对象)

2、进程本身运行需要的内存

3、缓冲内存

4、内存碎片

三、Redis数据存储的细节

1、概述

2、jemalloc

3、redisObject

4、SDS

四、Redis的对象类型与内部编码

1、字符串

2、列表

3、哈希

4、集合

5、有序集合

五、应用举例

1、估算Redis内存使用量

2、优化内存占用

3、关注内存碎片率

六、参考文献

一、Redis内存统计

工欲善其事必先利其器,在说明Redis内存之前首先说明如何统计Redis使用内存的情况。

在客户端通过redis-cli连接服务器后(后面如无特殊说明,客户端一律使用redis-cli),通过info命令可以查看内存使用情况:

1

info memory

其中,info命令可以显示redis服务器的许多信息,包括服务器基本信息、CPU、内存、持久化、客户端连接信息等等;memory是参数,表示只显示内存相关的信息。

返回结果中比较重要的几个说明如下:

(1)used_memoryRedis分配器分配的内存总量(单位是字节),包括使用的虚拟内存(即swap);Redis分配器后面会介绍。used_memory_human只是显示更友好。

(2)used_memory_rssRedis进程占据操作系统的内存(单位是字节),与top及ps命令看到的值是一致的;除了分配器分配的内存之外,used_memory_rss还包括进程运行本身需要的内存、内存碎片等,但是不包括虚拟内存。

因此,used_memory和used_memory_rss,前者是从Redis角度得到的量,后者是从操作系统角度得到的量。二者之所以有所不同,一方面是因为内存碎片和Redis进程运行需要占用内存,使得前者可能比后者小,另一方面虚拟内存的存在,使得前者可能比后者大。

由于在实际应用中,Redis的数据量会比较大,此时进程运行占用的内存与Redis数据量和内存碎片相比,都会小得多;因此used_memory_rss和used_memory的比例,便成了衡量Redis内存碎片率的参数;这个参数就是mem_fragmentation_ratio。

(3)mem_fragmentation_ratio内存碎片比率,该值是used_memory_rss / used_memory的比值。

mem_fragmentation_ratio一般大于1,且该值越大,内存碎片比例越大。mem_fragmentation_ratio<1,说明Redis使用了虚拟内存,由于虚拟内存的媒介是磁盘,比内存速度要慢很多,当这种情况出现时,应该及时排查,如果内存不足应该及时处理,如增加Redis节点、增加Redis服务器的内存、优化应用等。

一般来说,mem_fragmentation_ratio在1.03左右是比较健康的状态(对于jemalloc来说);上面截图中的mem_fragmentation_ratio值很大,是因为还没有向Redis中存入数据,Redis进程本身运行的内存使得used_memory_rss 比used_memory大得多。

(4)mem_allocatorRedis使用的内存分配器,在编译时指定;可以是 libc 、jemalloc或者tcmalloc,默认是jemalloc;截图中使用的便是默认的jemalloc。

二、Redis内存划分

Redis作为内存数据库,在内存中存储的内容主要是数据(键值对);通过前面的叙述可以知道,除了数据以外,Redis的其他部分也会占用内存。

Redis的内存占用主要可以划分为以下几个部分:

1、数据

作为数据库,数据是最主要的部分;这部分占用的内存会统计在used_memory中。

Redis使用键值对存储数据,其中的值(对象)包括5种类型,即字符串、哈希、列表、集合、有序集合。这5种类型是Redis对外提供的,实际上,在Redis内部,每种类型可能有2种或更多的内部编码实现;此外,Redis在存储对象时,并不是直接将数据扔进内存,而是会对对象进行各种包装:如redisObject、SDS等;这篇文章后面将重点介绍Redis中数据存储的细节。

2、进程本身运行需要的内存

Redis主进程本身运行肯定需要占用内存,如代码、常量池等等;这部分内存大约几兆,在大多数生产环境中与Redis数据占用的内存相比可以忽略。这部分内存不是由jemalloc分配,因此不会统计在used_memory中。

补充说明:除了主进程外,Redis创建的子进程运行也会占用内存,如Redis执行AOF、RDB重写时创建的子进程。当然,这部分内存不属于Redis进程,也不会统计在used_memory和used_memory_rss中。

3、缓冲内存

缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF缓冲区等;其中,客户端缓冲存储客户端连接的输入输出缓冲;复制积压缓冲用于部分复制功能;AOF缓冲区用于在进行AOF重写时,保存最近的写入命令。在了解相应功能之前,不需要知道这些缓冲的细节;这部分内存由jemalloc分配,因此会统计在used_memory中。

4、内存碎片

内存碎片是Redis在分配、回收物理内存过程中产生的。例如,如果对数据的更改频繁,而且数据之间的大小相差很大,可能导致redis释放的空间在物理内存中并没有释放,但redis又无法有效利用,这就形成了内存碎片。内存碎片不会统计在used_memory中。

内存碎片的产生与对数据进行的操作、数据的特点等都有关;此外,与使用的内存分配器也有关系:如果内存分配器设计合理,可以尽可能的减少内存碎片的产生。后面将要说到的jemalloc便在控制内存碎片方面做的很好。

如果Redis服务器中的内存碎片已经很大,可以通过安全重启的方式减小内存碎片:因为重启之后,Redis重新从备份文件中读取数据,在内存中进行重排,为每个数据重新选择合适的内存单元,减小内存碎片。

三、Redis数据存储的细节

1、概述

关于Redis数据存储的细节,涉及到内存分配器(如jemalloc)、简单动态字符串(SDS)、5种对象类型及内部编码、redisObject。在讲述具体内容之前,先说明一下这几个概念之间的关系。

下图是执行set hello world时,所涉及到的数据模型。

图片来源:https://searchdatabase.techtarget.com.cn/7-20218/

(1)dictEntry:Redis是Key-Value数据库,因此对每个键值对都会有一个dictEntry,里面存储了指向Key和Value的指针;next指向下一个dictEntry,与本Key-Value无关。

(2)Key:图中右上角可见,Key(”hello”)并不是直接以字符串存储,而是存储在SDS结构中。

(3)redisObject:Value(“world”)既不是直接以字符串存储,也不是像Key一样直接存储在SDS中,而是存储在redisObject中。实际上,不论Value是5种类型的哪一种,都是通过redisObject来存储的;而redisObject中的type字段指明了Value对象的类型,ptr字段则指向对象所在的地址。不过可以看出,字符串对象虽然经过了redisObject的包装,但仍然需要通过SDS存储。

实际上,redisObject除了type和ptr字段以外,还有其他字段图中没有给出,如用于指定对象内部编码的字段;后面会详细介绍。

(4)jemalloc:无论是DictEntry对象,还是redisObject、SDS对象,都需要内存分配器(如jemalloc)分配内存进行存储。以DictEntry对象为例,有3个指针组成,在64位机器下占24个字节,jemalloc会为它分配32字节大小的内存单元。

下面来分别介绍jemalloc、redisObject、SDS、对象类型及内部编码。

2、jemalloc

Redis在编译时便会指定内存分配器;内存分配器可以是 libc 、jemalloc或者tcmalloc,默认是jemalloc。

jemalloc作为Redis的默认内存分配器,在减小内存碎片方面做的相对比较好。jemalloc在64位系统中,将内存空间划分为小、大、巨大三个范围;每个范围内又划分了许多小的内存块单位;当Redis存储数据时,会选择大小最合适的内存块进行存储。

jemalloc划分的内存单元如下图所示:

图片来源:http://blog.csdn.net/zhengpeitao/article/details/76573053

例如,如果需要存储大小为130字节的对象,jemalloc会将其放入160字节的内存单元中。

3、redisObject

前面说到,Redis对象有5种类型;无论是哪种类型,Redis都不会直接存储,而是通过redisObject对象进行存储。

redisObject对象非常重要,Redis对象的类型、内部编码、内存回收、共享对象等功能,都需要redisObject支持,下面将通过redisObject的结构来说明它是如何起作用的。

redisObject的定义如下(不同版本的Redis可能稍稍有所不同):

1

2

3

4

5

6

7

typedefstructredisObject {

unsigned type:4;

unsigned encoding:4;

unsigned lru:REDIS_LRU_BITS;/* lru time (relative to server.lruclock) */

intrefcount;

void*ptr;

} robj;

redisObject的每个字段的含义和作用如下:

(1)type

type字段表示对象的类型,占4个比特;目前包括REDIS_STRING(字符串)、REDIS_LIST (列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)。

当我们执行type命令时,便是通过读取RedisObject的type字段获得对象的类型;如下图所示:

(2)encoding

encoding表示对象的内部编码,占4个比特。

对于Redis支持的每种类型,都有至少两种内部编码,例如对于字符串,有int、embstr、raw三种编码。通过encoding属性,Redis可以根据不同的使用场景来为对象设置不同的编码,大大提高了Redis的灵活性和效率。以列表对象为例,有压缩列表和双端链表两种编码方式;如果列表中的元素较少,Redis倾向于使用压缩列表进行存储,因为压缩列表占用内存更少,而且比双端链表可以更快载入;当列表对象元素较多时,压缩列表就会转化为更适合存储大量元素的双端链表。

通过object encoding命令,可以查看对象采用的编码方式,如下图所示:

5种对象类型对应的编码方式以及使用条件,将在后面介绍。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 4:51:55

[Power节点]原理解析与实际应用

Power节点是Unity ShaderGraph中的核心数学工具&#xff0c;用于计算输入值A的B次幂&#xff08;即输出OutA^B&#xff09;。该节点通过指数运算实现非线性变换&#xff0c;能够以指数方式增强或减弱输入值&#xff0c;适用于需要动态调整强度或创建复杂效果的场景。例如&#…

作者头像 李华
网站建设 2026/7/2 4:51:48

JS-前端埋点神器 navigator.sendBeacon 全指南

前端开发中&#xff0c;埋点系统是必不可少的一环。我们经常需要在用户关闭页面、刷新或跳转路由时&#xff0c;向服务器发送最后一条统计数据&#xff08;比如用户停留时长、页面跳出率&#xff09;。 但这看似简单的需求&#xff0c;在实现时却危机四伏&#xff1a;请求发不…

作者头像 李华
网站建设 2026/7/2 4:51:08

京东商品详情全自动采集实战|标准化 JD 商品详情接口 + 多 AI Agent 搭建无人化货源分析系统

做京东货源采购、竞品调研、跨平台铺货、自研进销存系统的开发者和运营&#xff0c;都会频繁需要完整商品结构化数据。京东区分自营、工业、医药、全球购多个业务站点&#xff0c;不同站点页面字段展示逻辑存在差异&#xff0c;如果手动打开页面复制标题、售价、尺码规格、主图…

作者头像 李华
网站建设 2026/7/2 4:50:40

VS2022 远程调试 CentOS 进程全指南:轻松附加到运行中的程序

在跨平台开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;程序在本地 Windows 环境下编译&#xff0c;但实际运行和测试环境却在远程的 Linux 服务器&#xff08;如 CentOS&#xff09;上。当程序在服务器上出现异常时&#xff0c;如何高效地进行排查&#xff1f;答案是…

作者头像 李华
网站建设 2026/7/2 4:49:27

不是技术也能看懂云计算,大数据,人工智能

云计算最初是实现资源管理的灵活性我们首先来说云计算&#xff0c;云计算最初的目标是对资源的管理&#xff0c;管理的主要是计算资源&#xff0c;网络资源&#xff0c;存储资源三个方面。1.1 管数据中心就像配电脑什么叫计算&#xff0c;网络&#xff0c;存储资源呢&#xff1…

作者头像 李华
网站建设 2026/7/2 4:49:20

UFS 4.1规范的量产烧录:从MIPI M-PHY V4.1到UniPro V2.0的协议适配分析

引言 在JEDEC固态技术协会正式发布UFS 4.1规范后&#xff0c;存储原厂的晶圆厂与封装测试产线随之迎来了一场低调但严苛的博弈。对于FT&#xff08;封装后测试&#xff09;与产品工程师而言&#xff0c;UFS 4.1带来的翻倍带宽并不只是数据表上的漂亮数字&#xff0c;它意味着产…

作者头像 李华