Redis的ZipList和QuickList和SkipList和RedisObject

news2024/10/7 6:49:11

ZipList:压缩列表,为了节省内存而设计的一种数据结构

ZipList是一种特殊的双端链表,是由一系列的特殊编码的连续内存块组成,不需要通过指针来进行寻址来找到各个节点,可以在任意一端进行压入或者是弹出操作,并且该操作的时间复杂度是O(1);

dict底层是依靠依靠哈希表来实现的,虽然查询性能比较高,但是一个指针要占用8个字节,大量使用指针寻址(因为内存不连续,要通过指针寻址)会浪费内存,况且这种链式存储方式极其容易产生内存碎片;

因为在压缩列表中,存放不同的数据所占用的内存是不一样的,Entry值越大,占用字节数越大在ZipList中,Entry并不像普通链表一样进行记录前后点的指针,因为每记录两个指针要占用16个字节,浪费内存,而是使用了下面的结构

1)previous_entry_length:前一个结点的长度,占用1个字节或者是5个字节

1.1)如果前一个结点的长度小于254个字节,那么就采用1个字节来保存这个长度值;

1.2)如果前一个结点的长度大于254个字节,那么就采用5个字节来保存这个长度的值,第一个字节是OXFE,后四个字节才是真实的长度数据;

2)encoding:编码属性,记录content的数据类型字符串还是整数以及长度,Encoding本身的长度占用1个,2个或者是5个字节,况且只是存在这两个值

ZipListEntry中的encoding编码分为字符串和整数两种

1)字符串:如果Encoding是以00或者01或者是10来进行开头的那么证明content是字符串类型,下面的p和q是用来记录字符串的长度的;

假设现在要保存"ab"和"bc"这两个字符串

第一部分是表示前一个字符串的长度,第二部分是表示采用00编码,并且所存储的字符串长度是2,第三部分是实际存储的字符串的ASCIL值;

 

下面是使用16进制编码的形式来进行存储

 整个压缩列表的结构:

2)整数:如果encoding是以11开头,那么就证明content是整数,况且encoding固定只是使用1个字节,因为整数值长度固定,来记录四种字节数,就不需要记录长度了

3)1111是结束标识,显然最后一种编码形式不能使用,0000和1110在其他编码中已经使用了,所以范围就是0001-1101,就是0-12

假设我们现在所进行存储的两个整数值是2和5那么ZipList就会直接将这两个值保存到Encoding中,就不需要0-12了

 

ZipList的连锁更新问题:

现在假设我们有N个连续的,长度在250-253个字节之间的Entry,因此Entry的previous_entry_length属性用一个字节就可以进行表示:

现在有一个长度是254的entry插入到了这个ZipList的头节点,此时原第一个的previous_entry_length的长度就会发生变化,不得不采用5个字节来进行表示,后面就会产生多个Entry的previous_entry_length发生变化,本来是一段连续的内存空间,如果原来的第一个节点要多申请4个字节,所有的数据都会发生迁移,如果原有的内存空间不够还会发生扩容,新增空间,会频繁的进行内存申请,数据迁移的动作

ZipList这种特殊情况下产生的来纳许多次空间扩展操作称之为是连锁更新,新增和删除操作都有可能会出现连锁更新的情况 

ZipList的特性: 

1)压缩列表的可以看作是一种连续内存空间的双向链表,连续内存空间不大还好,但是如果你申请的是较大的连续内存空间,再去申请内存就比较麻烦了,因为内存往往是碎片化的,如果你想要申请一大块的连续内存,往往是比较困难的,所以ZipList不能存放过多的数据

2)列表的节点之间不是通过指针连接,而是记录上一个节点和本节点长度进行寻址,内存的占用比较低

3)如果列表中的数据过多,可能会导致链表过长,可能会影响查询性能

4)增或者删较大数据的时候可能会发生previous_entry_length连续更新问题

QuickList介绍:内存占用比较少

问题1:ZipList虽然节省内存,但是申请的内存必须是连续的内存空间,如果内存占用过高导致内存的申请效率比较低怎么办?

为了缓解这个问题可以创建多个ZipList来分片存储数据

问题2:但是要创建和存储大量数据,超过了ZipList的最佳上限怎么办?

可以创建多个ZipList来进行分片存储数据

问题3:数据拆分后比较分散,不方便进行管理和查找,这多个ZipList之间该如何建立联系?

Redis在3.2版本之后引入了新的数据结构QuickList,他是一个双端链表,只不过是链表中的每一个节点都是一个ZipList

 

 进行读取ZipList的时候做解压缩,进行存储ZipList的时候会做压缩

 总结:QuickList

1)QuickList本身是一个节点是ZipList的双端链表

2)节点是采用ZipList,解决了传统链表的内存占用问题,但是ZipList不建议存储节点过多,因为会产生连续内存空间申请效率变低

3)所以为了解决上述问题,Redis就控制了ZipList的大小,解决了连续申请内存空间效率较低的问题

4)中间节点可以进行压缩,可以节省内存空间

5)虽然QuickList和ZipList都很节省内存空间,但是对于遍历元素来说还是比较麻烦的,因为他们遍历元素的时间复杂度都是O(N)

SkipList

SkipList底层的实现是依据跳表来实现的,他和传统的链表是具有一定差异的

1)元素按照升序排列进行存储

2)节点可能包含着多个指针,指针的跨度不同

1)level:链表越长,可能level的层级也是大的,如果链表越短,可能level的层级也是越短的,将来进行查询的时候,肯定是从层级最高的索引向下进行查询的;

2)在一个节点中,score是存放着对应的值,而SDS是节点所进行存储的字符串

3)在一个节点的结构体中,存在着一个level数组,里面存放的是这个数组包含了多少级指针,以及每一个对应的指针的跨度,这个数组可能包含一个元素,就是指是存在着一级指针,也有可能存在着多个元素,但是至少要存在一个一级指针;

4)当数组从后向前进行查找的时候,只是通过backward指针从后向前进行遍历;

但是从head向tail进行遍历的时候就可以通过level的多级指针来进行查找;

5)链表越长,指针层级也就越多,进行查找元素也是十分方便

下面是所有节点都是一级指针的结构:

下面是部分节点包括二级指针的结构:

下面是部分节点包括三级指针的结构:

SkipList的特点:

1)跳表是一个双向链表,每一个节点都包含着score值和ele值,score值是得分,将来要依靠score值来进行排序,ele就是节点中要保存的一个数据,本质上是一个SDS字符串

2)节点会按照score值做升序排序,score值相同那么按照ele字典进行排序

3)每一个节点都可以包含多级指针,层数是1-32之间的随机数

4)在一个节点中,不同的层级指针到下一个结点的跨度是不相同的,层级越高跨度就越大

5)增删改查效率和红黑树基本一致,实现起来确实更简单

RedisObject:不包括指针指向的内存空间,至少占有40个字节

Redis任意的数据类型的键和值都会被封装成一个RedisObject,也叫做Redis对象,源码如下

并不推荐经常使用String类型,因为挺浪费内存空间的,假设现在有10个字符串都使用String类型进行存储,那么至少需要10个RedisObject来存储String类型的头信息,于是就被浪费掉了400个字节,而在同等情况下如果使用List数据结构,那么RedisObject的个数就会大量地减少

Redis会根据所存储的数据结构的不同会选择不同的编码方式,一共有11种类型

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/608758.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RocketMQ的学习历程(5)----broker内部设计

文章目录 概要整体架构流程技术名词解释CommitLog和ConsumeQueue页缓存和内存映射刷盘机制 小结 概要 在首个学习历程中,我们已经了解了,RokctMQ简单的工作流程。 如果想要更深的理解RokcetMQ消息处理的流程,broker内部流程的理解是必要的&…

【挑战全站最全】Linux系统的安装与配置教程——以CentOS为例

🚀作者:那个叫马尔的大夫🚀 ⭐专栏:操作系统⭐ 🌼内容:主要分享一些关于Linux操作系统的知识 🥧不忘初心,砥砺前行~ 目录 一、用到的软件环境——虚拟机软件(必需&#…

调用函数不仅仅只是传递正确的参数类型

这里有一个新手犯下的一个典型错误。 假设,我们想调用这个函数,GetBinaryType。 void sample() { if (GetBinaryType(TEXT(“explorer.exe”), ????)) { … } } 请问,这里的问号处应该传递什么类型的参数?你可能会说&#x…

python、pyqt5实现人脸检测、性别和年龄预测

摘要:这篇博文介绍基于opencv:DNN模块自带的残差网络的人脸、性别、年龄识别系统,系统程序由OpenCv, PyQt5的库实现。如图系统可通过摄像头获取实时画面并识别其中的人脸表情,也可以通过读取图片识别,本文提供完整的程…

设计模式入门:策略模式

现有一套模拟鸭子游戏,可以一边游泳,一边呱呱叫。 每种鸭子都会呱呱叫和游泳,只是外观不同。因此,quack和swim放在父类中,display放在子类中实现。 增加新的功能:鸭子飞翔。 1 我们可能想到直接在父类中增…

LeetCode——最小化字符串长度

目录 一、题目 二、题目解读 三、代码 1、set去重 2、用一个二进制数记录每个字母是否出现过 一、题目 6462. 最小化字符串长度 - 力扣(Leetcode) 给你一个下标从 0 开始的字符串 s ,重复执行下述操作 任意 次: 在字符串…

聊一聊数据库事务的那些事(隔离级别,传播行为)

我们平时使用事务的时候,可能脑子里面想到和事务有关的知识点无非就是,ACID,事务隔离级别那一套,使用的事务也就是是通过注解的形式,或者手动开启事务。更细致一点的问题或许没有深究下去,比如事务的传播行…

STM32F407的PWM

文章目录 32的PWM资源PWM输出原理捕获/比较模式寄存器(TIMx_CCMR1/2)捕获/比较使能寄存器(TIMx_CCER)捕获/比较寄存器(TIMx_CCR1~4) 库函数版本的PWM波输出开启 TIM3 时钟以及复用功能时钟置 ,配…

对CT数据进行最小最大值归一化(Min-Max Normalization)和消除过暗过亮值处理

文章目录 PIL库的图像失真问题使用最小最大值归一化(Min-Max Normalization)预处理消除过暗过亮值pytorch中对tensor使用最小最大值归一化处理(torchvision.transforms) 我们在处理CT图像时(以dcm格式为例)…

全栈小程序开发路线

目录 个人心得: 我的学习路线 个人心得: 我擅长的是小程序开发和技术变现,从2021年至今开发上线20于个小程序,矩阵用户超过10万,变现10万左右。 以下是部分小程序截图,追风口做的小程序,基本…

「Win」Windows注册表介绍与操作

✨博客主页:何曾参静谧的博客 📌文章专栏:「Win」Windows程序设计 相关术语 Windows的注册表:是一个重要的系统组件,用于存储操作系统和应用程序的配置信息。它类似于一个数据库,包含了各种键值对、参数、设…

Vue报错:Error: error:0308010C:digital envelope routines::unsupported解决

问题 node 环境 Node.js v18.14.2 使用npm start.出现以下报错 Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:71:19) at Object.createHash (node:crypto:133:10) at module.exports (F:\RuoYi-Cloud\CourseSched…

SWAT模型系统学习(建模方法、实例应用、高级进阶)

目前,水环境问题逐渐成为制约社会经济和环境可持续发展的重要因素。根据国内外研究表明,受全球环境变化和经济快速发展的影响,面源污染已逐渐成为水环境污染的第一因素。但面源污染由于具有排放分散、隐蔽,排污随机、不确定、不易…

搜索算法(三) 回溯法

1.回溯法 回溯法可以理解成一种特殊的深度优先算法,比起普通的DFS,多了还原当前节点的一步。 修改当前节点、递归子节点、还原当前节点。 本质是一种试错的思想。 维基百科: 2.例题 1) 力扣https://leetcode.cn/problems/pe…

树莓派安装系统

0. 实验准备 树莓派一个,TF卡(4GB以上)一个,读卡器一个 1. 使用官方提供的工具 在搜索引擎中搜索树莓派(不要用百度,建议使用必应的国际版进行搜索),我这里直接放上树莓派官方超链…

深入篇【Linux】学习必备:理解【Linux软件包管理器】yum + yum的具体使用 + yum下载的有趣指令

这里写目录标题 Ⅰ.Linux软件包管理器yum①.什么是软件包/什么是yum②.linux的软件生态与yum源③.关于rzsz Ⅱ.yum基本指令①.查看软件②.安装软件③.卸载软件 Ⅲ.yum下载的好玩指令①.sl②.linux_logo③.elinks Ⅰ.Linux软件包管理器yum yum 是一个 Shell 前端软件包管理器。基…

C++ 多态 最详细图文+代码讲解

感谢各位 点赞 收藏 评论 三连支持 本文章收录于专栏【C进阶】 ❀希望能对大家有所帮助❀ 本文章由 风君子吖 原创 回顾 上篇文章,我们学习了继承的相关知识,详细解刨了继承中的各种细节,而本章内容将在继承的基础上学习多态 多态的概念…

Dreamweaver如何进行网页开发?

文章目录 0.引言1.安装Dreamweaver2.编写第一个网页 0.引言 笔者本科学习的编程语言主要是关于桌面开发的,对编程有一定的基础,而编程除了关于桌面软件开发(VisualStudio如何进行桌面软件开发?),还有手机应…

网络安全自学笔记+学习路线(超详细)

01 什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面…

c语言编程练习题:7-193 两小时学完C语言

#include <stdio.h> int main(){int n,k,m;int sum;if (scanf("%d %d %d",&n,&k,&m)!EOF){sum n-k*m;}printf("%d",sum);return 0; }