当前位置: 首页 > news >正文

Redis八种数据结构简介

Redis数据结构

Redis新旧版本中一共出现过八种数据结构,分别是SDS、双向链表、压缩列表、整数集合、哈希表、跳表、quicklist、listpack。

SDS

SDS是用于存储Redis中字符串的数据结构,Redis底层使用的语言是C语言,因此字符串也是C语言的字符串。然而C语言字符串存在一些问题。

1.获取长度时间复杂度为O(N),因为C语言中没有预置的字符串数据类型,而是用一个以“/0”结尾的字符数组代替的,所以要获取字符串长度的话就需要遍历整个数组,数组长度越大消耗时间就越多。

2.无法存储二进制数据,因为C语言字符串就是以"/0"结尾的字符数组,所以如果存储二进制数据的话可能会含有/0的内容,会混淆数组结尾的/0。

3.存在缓冲区溢出的风险,因为C语言不像Java等语言有自己的自动内存管理机制(如Java的垃圾回收器),而是依靠程序员手动管理内存,因此字符数组在添加内容时就可能会导致缓冲区溢出的问题。

为了解决这些问题,Redis中的字符串在原来的基础上添加了三个元数据,分别是len、alloc、flags,分别代表长度、空间长度、SDS类型。具体来说,len记录了字符串的长度,这样在获取字符串长度的时候直接从这个字段获取就行,时间复杂度为O(1),而且由于len表明了字符串的长度,因此字符串最后一位就不是必须使用“/0”结尾,所以可以存储二进制数据;

alloc则记录了字符串的空间大小,在修改字符串的时候首先会查看alloc大小是否满足,如果不满足的话会进行扩容(小于1MB翻倍,大于1MB增加1MB),这样就能避免缓冲区溢出的问题;

flags用来表示不用类型的SDS,一共有5种类型,分别是sdshdr5、sdshdr8、sdshdr16、sdshdr32和sdshdr64。这五种类型的区别在于数据结构中的len和alloc成员变量的数据类型不同,因此字符串可以用来存放不同类型的数据而不是只能为原来的字符型。

链表

由于C语言中没有链表这一数据结构,所以Redis自己实现了一个双向链表的数据结构。对于每一个节点来说,拥有前置节点、后置节点、节点值三个属性,而链表在节点的基础上封装了头结点、尾结点、节点复制函数、节点释放函数、节点比较函数、链表节点数量等属性和方法。

对链表的属性和方法中可以看出,该链表对于获取节点的上/下一个节点、头/尾节点、节点数量等操作都非常快,而且链表节点中可以保存不同类型值。

但是也有缺陷,因为链表和数组不同,内存地址并不是连续的,所以不像数组那样可以充分利用CPU缓存加速访问;而且每添加一个节点都需要为其元数据等添加额外的内存,增加了内存的开销。

压缩列表

压缩列表相对于链表来说,内存地址是连续的,和数组一样可以充分地利用CPU缓存,提高了查询的速度,而且会针对不同长度的数据进行相应编码,这种方法能有效地节省内存开销。

在Redis中,List、Hash、Zset等数据类型在包含的元素数量较少的情况下才会使用到压缩列表存储数据。

除此之外,其他和列表不同的是,压缩列表在表头有几个默认字段,分别为zlbytes(列表占用内存的字节数)、zltail(列表尾部的偏移量,可以理解为列表的容量大小)、zllen(列表包含的节点数量)、zlend(列表的结束点)。这些字段能够帮助快速获取列表大小、高效访问尾元素、元素数量等。

压缩列表中的节点也有自己的元数据,分别为prevlen(前一个节点的长度)、encoding(当前节点的数据类型和长度)、data(当前节点的实际数据)。由此可以看出不同节点的空间大小会根据其实际的数据类型进行分配,节省了内存。

连锁更新问题:由于一个节点中有prevlen属性,记录上一个节点的大小,因此当插入节点的时候,如果插入节点的下一个节点中的prevlen长度不足以标明节点的大小的时候那么就需要更新下一个节点的大小,也就是增加其prevlen属性大小,进而也就改变了下一个节点的大小,以此类推也可能改变其他节点。

尽管压缩列表能够通过连续地址和类型分配节省内存,提供一些较为高效的数据操作,但是当其所包含的元素数量过多时,由于是一片连续的内存空间,就可能导致重新分配内存地址,导致性能下降。

哈希表

Redis中的哈希表是一个数组,每个元素指向哈希表节点,哈希表节点中除了值以外还有指向下一个哈希表节点的指针,形成单向链表,因此和Java中的hashmap类似,使用链表的结构存放hash冲突的元素。

不过这里的负载因子算法是哈希表中的节点数/哈希表大小,因此当负载因子大于等于1的时候就需要进行扩容(rehash)操作。

整数集合

当一个Set中只有整数值元素的时候就会使用整数集这个数据结构作为底层实现。

当将一个新元素添加进整数集合的时候并且这个元素的长度大于整数集合中的最大元素长度时就会触发整数集合的升级,一旦升级后就无法降级。由于添加新的元素才触发升级,所以这个机制能够节省内存资源。

跳表

Redis中唯一使用到了跳表的数据类型是Zset(Zset中使用到了跳表+哈希表两种数据结构),跳表这一数据结构能够实现范围查询。

链表查询元素效率很低,而跳表在链表的基础上实现了一种多层结构,简单来说就是按照一定的跨度(两个节点之间的距离)将原来的链表进行了分层,不同的跨度能够实现跳跃式的查询。因此,跳表中存在多级索引,占用的空间较大,但是查询效率得到提升。

quicklist

在Redis3.2后,list数据类型的底层实现由原来的双向链表或压缩列表改为了quicklist,解决了由于压缩列表无法存储大量数据的问题。

quicklist的结构和链表类似,但是将链表的每个元素改为设置一个压缩列表,并且控制每个链表节点中压缩列表的大小,这样就能利用压缩列表的优势同时避免了一个压缩列表存储大量数据的问题。

在quicklist中并不是所有元素都会进行压缩,在两端处有一些数据会频繁地进行操作(像lpush、rpush、lpop、rpop等操作都是直接访问两端节点数据),因此这部分数据可以不用进行压缩,以减少性能损耗,除此之外如果有的压缩列表中只有一个元素,那也不会为之创建一个压缩列表。

quicklist允许对数据进行压缩,原理是如果数据与之前的数据重复,则只会记录重复的位置和重复的长度。

listpack

虽然quicklist降低了连锁更新的概率和造成的影响,但是没有完全避免,因为数据结构中还是用了压缩列表,因此Redis在5.0后设计了一个新的数据结构listpack来替代压缩列表,在listpack中取消了prevlen字段,避免了因为更新而可能需要不断更新相邻节点的prevlen的隐患。

listpack头也有两个属性,分别为listpack总字节数和元素数量,在尾部有结尾标识。

每个listpack节点中有len,encoding,data三个字段,其中encoding定义元素的编码类型,data为实际存放的数据,len则是encoding+data的总长度。所以listpack节点没有记录前一个节点长度,而是只记录当前节点长度,所以向listpack中加入新元素的时候不会影响其他节点,进而避免了连锁更新问题。

由于取消了prevlen字段,listpack无法像压缩列表那样进行双向遍历,但是节省了内存,避免了连锁更新。

相关文章:

Redis八种数据结构简介

Redis数据结构 Redis新旧版本中一共出现过八种数据结构,分别是SDS、双向链表、压缩列表、整数集合、哈希表、跳表、quicklist、listpack。 SDS SDS是用于存储Redis中字符串的数据结构,Redis底层使用的语言是C语言,因此字符串也是C语言的字…...

数据治理策略:确保数据资产的安全与高效利用

数据治理策略:确保数据资产的安全与高效利用 在数字化时代,数据已成为企业最宝贵的资产之一。然而,随着数据量的爆炸性增长和数据来源的多样化,如何有效地管理和利用这些数据成为企业面临的重要挑战。数据治理策略的制定和执行&a…...

ts格式转mp4,四款亲测好用软件推荐!

在这个数字视频时代,我们经常会遇到各种视频格式兼容性问题,尤其是从网络下载的高清电影或电视剧集,很多时候都是以TS格式存储。然而,当我们想要在移动设备、社交媒体或视频编辑软件中播放、上传时,MP4格式因其广泛的兼…...

10、Django Admin修改标题

admin from django.contrib import admin from .models import Category, Origin, Hero, Villain # 添加以下代码 admin.site.site_header "系统管理" admin.site.site_title "管理员界面" admin.site.index_title "欢迎来到这里&#xff…...

ESRI ArcGIS Pro 3.1.5新功能及安装教程和下载

ESRI ArcGIS Pro 3.1.5 主要新功能包括: 改进的数据编辑和管理:支持更多数据格式和更精细的属性表操作。增强的空间分析工具:新增和优化空间分析工具,提高数据分析效率。更好的3D可视化:改进3D渲染性能,支…...

人工智能,语音识别也算一种人工智能。

现在挺晚了,还是没有去睡觉,自己在想什么呢,也不确定。 这是一篇用语音写的文章,先按自己的想法说出来,然后再适当修改,也许就是一个不错的文章。 看来以后就不需要打字了,语音识别度很高&#…...

Token和Refresh Token

获取令牌(Token) 和 刷新令牌(Refresh Token) 在认证和授权机制中有不同的使用场景和目的,二者主要的区别和为什么需要刷新令牌可以通过以下几点解释: 1. 获取令牌和刷新令牌的区别 获取令牌(Token&#x…...

STM32(一)简介

一、stm32简介 1.外设接口 通过程序配置外设来完成功能 2.系统结构 3.引脚定义 4.启动配置 5.最小系统电路...

接口测试工具:Postman详解

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、前言 在前后端分离开发时,后端工作人员完成系统接口开发后,需要与前端人员对接,测试调试接口,验证接口的正确性…...

Linux中全局变量配置,/etc/profile.d还是/etc/profile

全局环境变量可以放在 /etc/profile 或 /etc/profile.d/ 中,但两者的使用方式和目的有所不同: /etc/profile 作用: /etc/profile 是一个系统范围的启动脚本,在用户登录时执行。它主要用于设置全局环境变量和配置,适用于所有用户。…...

【java入门】关键字、标识符与变量初识

🚀 个人简介:某大型国企资深软件开发工程师,信息系统项目管理师、CSDN优质创作者、阿里云专家博主,华为云云享专家,分享前端后端相关技术与工作常见问题~ 💟 作 者:码喽的自我修养&#x1f9…...

Java常用类库

Java常用类库 1. **Java基础类库**1.1 **java.lang**1.2 **java.util**1.3 **java.io**1.4 **java.nio**1.5 **java.time** 2. **第三方类库**2.1 **Apache Commons**2.2 **Google Guava**2.3 **Jackson**2.4 **Lombok** 3. **Spring相关类库**4. **并发类库**4.1 **java.util.…...

2024年高教社杯数学建模国赛C题超详细解题思路分析

本次国赛预测题目难度,选题人数如下所示 难度评估 A:B:C 1.8:1.3:1 D:E1.5:1 选题人数 A:B:C 1:1.5:2.8 D:E0.5:1.2 C题一直以来都是竞赛难度最低、选题人数最多的一道本科生选题,近三年C题的选题人数一直都是总参赛队伍的一半左右,2023年…...

深度学习(七)-计算机视觉基础

计算机视觉 计算机视觉在广义上是和图像相关的技术总称。包括图像的采集获取,图 像的压缩编码,图像的存储和传输,图像的合成,三维图像重建,图像增强,图像修复,图像的分类和识别,目…...

机器人笛卡尔空间轨迹规划原理与MATLAB实现

机器人笛卡尔空间轨迹规划是指在给定的笛卡尔坐标系(通常是三维空间坐标系)中规划机器人的末端执行器(如抓手、焊枪等)的移动路径。这种规划方式直观且易于理解,因为它直接关联到任务空间中机器人的位置和姿态。下面将…...

数据结构:树与二叉树

1、树的基本概念 1.1树的定义 树是n个结点的有限集。 若n0,称为空树;若n>0称为非空树,非空树有且仅有一个称之为根的结点。 除根结点以外的其余结点可分成m个互不相交的有限集T1,T2,......Tm,每个有限集合本身又是一棵树,并…...

BUUCTF—[网鼎杯 2020 朱雀组]phpweb

题解 打开题目是这样子的。 啥也不管抓个包看看,从它返回的信息判断出func后面的是要调用的函数,p后面的是要执行的内容。 那我们直接执行个系统命令看看,可以看到返回了hack,估计是做了过滤。 funcsystem&pls 直接读取源码…...

什么是CDN及其如何影响SEO?

有没有想过,为什么你的网站在谷歌搜索结果的后几页徘徊,即使你已经优化了每一个网页? 有时候, 慢速的网站性能可能是罪魁祸首。 如果这个问题引起了你的共鸣,那么你可能想要探索一下内容分发网络(Content…...

python实现粒子群算

博客目录 引言 什么是粒子群算法(PSO)?粒子群算法的应用场景为什么使用粒子群算法? 粒子群算法的原理 粒子群算法的基本概念粒子位置和速度的更新规则粒子群算法的流程粒子群算法的特点与优势 粒子群算法的实现步骤 初始化粒子群…...

【Unity案例】搭建射击系统与UI

上期将基础的移动系统搭建完毕后就可以开始搭建更加复杂的系统部分了 前排提示,由于一开始仅思考如何完成操作相关功能,以至于到后面重构稍微有些困难,继续写下去恐成屎山,故在搭完射击和武器UI后不再继续泛化到敌人和敌人状态机…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

synchronized 学习

学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求&#xff…...

SpringCloudGateway 自定义局部过滤器

场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...