文章出处:
Redis内存模型及应用解读 https://dbaplus.cn/news-158-2127-1.html
第一部分:Redis内存统计
随笔:这一部分略显枯燥,是通过redis-cli连接redis后对于info命令的结果字段解读,属于较底层的部分,熟悉redis在操作系统中的实现会更容易理解这部分。
这段对于我的帮助
1、redis进程运行本身会需要内存和内存碎片,同时redis中还存在虚拟内存
2、mem_fragmentation_ratio表示内存碎片比率,mem_fragmentation_ratio<1,说明Redis使用了虚拟内存,应及时排查,如内存不足需及时处理,可以增加Redis节点、增加Redis服务器的内存、优化应用等
3、redis中的内存分配器分为libc 、jemalloc和tcmalloc,默认是jemalloc
这一部分在日常开发中不会经常用到,除非redis出现一些读写问题时可以结合本章排查。
第二部分:Redis内存划分
随笔:本章主要介绍Redis中的内存划分,简明扼要,对于第一部分的理解也有帮助,对于下文的理解应该也很重要
这段对于我的帮助
1、redis的内存分为数据内存、进程本身运行需要的内存、缓冲内存和内存碎片
2、redis是一种数据库,使用键值对这种方式存储数据,类似hashMap,存储的数据类型包括字符串、哈希、列表、集合和有序集合
3、内存碎片是由于数据的修改频繁导致redis对内存释放的处理异常而产生的,我会拿mysql的数据删除索引却没有明显变小来类比,都是由于既有逻辑对于存储的管理不当导致的,mysql可以使用analyze table来处理,redis同样也可以通过安全重启,本质上都是一样的操作
本章是一个非常好的承上启下章节,可以在理解上文的同时,更好的引入下文,也让我对redis对内存有了更多的了解。
第三部分:Redis数据存储的细节
随笔:第三部分的内容偏多,干货也是不少。主要介绍了redis底层存储数据的结构、jemalloc内存分配器简介、RedisObject这个redis基本对象的字段含义以及SDS的结构和优势
这段对于我的帮助
1、了解redis底层的存储接口,了解dictEntry、redisObject以及SDS的含义、结构和关系
2、了解jemalloc内存分配器对于内存的划分和管理
3、详细了解RedisObject的所有对象的含义和作用,包括用于内存回收的lru和refcount字段,以及共享字段的特性和使用,redisObject对于理解redis的存储机制起到至关重要的作用
4、SDS是redis自定义的一个字符串存储结构,本章拿SDS与c字符串对比,了解到SDS是一个非常巧妙和优美的代码结构,可以轻松应对许多c字符串处理起来非常头疼的场景
本章介绍偏底层,但通过本章介绍能够轻松理解redis的设计思路与储存方法,不仅对下文深入理解打好良好的基础,同时也可以在以后自设计的系统中参考其中优美的设计与逻辑。
第四部分:Redis的对象类型与内部编码
随笔:本文占据较大篇幅,主要是介绍redis的5种数据结构,他们的编码结构以及转换规则等
这段对于我的帮助
1、字符串类型的数据结构最大不能超过512M,包含3种编码,int编码仅存储值为整型的字符串,embstr编码仅存储<=39字节的字符串,同时embstr是只读的,当需要修改时,自动变成raw编码,raw编码存储超过long最大长度的int编码和超过embstr长度或embstr修改后的字符串,需要注意的是,redis的所有编码变化只能以小向大转化,该过程不可逆。
2、列表类型的数据结构是有序的字符串,一个列表可以存储2^32-1个元素,内部编码包括压缩列表(ziplist)和双端链表(linkedlist),双端链表由一个list结构和多个listNode结构组成,压缩列表是由一系列特殊编码的连续内存块(而不是像双端链表一样每个节点是指针)组成的顺序型数据结构,列表元素数量小于512个且都不足64字节时会使用压缩列表,否则使用双端链表。
3、哈希类型的数据结构内部编码包括压缩列表(ziplist)和哈希表(hashtable)两种,Redis外层只是哈希表,哈希中元素数量小于512个且键和值字符串长度都小于64字节时使用压缩列表编码结构,否则使用哈希表结构。
4、集合类型的数据结构与列表结构类似,但集合是无序的,并且集合元素不能重复,一个集合最多可以存储2^32-1个元素,除了支持常规的增删改查,Redis还支持多个集合取交集、并集、差集。内部编码为整数集合(intset)或哈希表(hashtable)。集合中元素数量小于512个且都是整型时使用整数集合,否则使用哈希表。
5、有序集合与集合相似,不同的是,会为每个元素设置一个分数(score)作为排序依据,内部编码为压缩列表(ziplist)或跳跃表(skiplist)。跳跃表是一种有序数据结构,通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的,跳跃表支持平均O(logN)、最坏O(N)的复杂点进行节点查找,并支持顺序操作。Redis的跳跃表实现由zskiplist和zskiplistNode两个结构组成:前者用于保存跳跃表信息(如头结点、尾节点、长度等),后者用于表示跳跃表节点。有序集合中元素数量小于128个且所有成员长度都不足64字节时使用压缩列表,否则使用跳跃表。
本章节对redis所有存储类型都做了详细对编码结构介绍,对理解redis内部存储结构有很大对帮助。可惜的是对于跳跃表的结构没有做太详细的介绍。
第五部分:应用举例
随笔:本章节主要针对redis的内存,提出预估、优化的方法,对于实践中有redis内存压力的案例会有帮助
这段对于我的帮助
1、内存使用量的预估可以根据上文说明的数据编码结构与结构大小来预估,文中有详细的案例说明
2、优化内存可以通过减少key或字符串的字节数,尽量使用整型与共享对象来实现,另外要避免过度设计
3、需要关注内存碎片率,上文提到的mem_fragmentation_ratio值,针对该值做一些处理和回收策略
总结:本文主要介绍了redis的内部储存方式、编码结构、内存分配器的工作与部分内存优化相关的内容,侧重点在存储结构上,不算非常全面的介绍文章,对于存储的介绍较为详细,但也没有类似压缩列表和跳跃表的结构和存储介绍,本文对于dba同学是必须要掌握的知识点,后端开发大致了解即可。
原文地址:https://www.cnblogs.com/dtt-java/p/11767197.html