Redis数据对象

news2024/12/22 6:20:51

基本结构图

key和value指向的是redisObject对象

type:标识该对象用的是什么类型(String、List

Redis数据结构

SDS

SDS有4个属性:

  • len:记录了字符串长度,因此获取字符串长度的时候时间复杂度O(1)
  • alloc:分配给字符数组的空间长度。这样在修改字符串的时候,只需要alloc-len来判断剩余空间大小,可以用来判断空间是否满足修改条件,如果不满足就会将SDS扩容。因此不会出现C语言的缓冲区溢出问题
  • flags:用来表示不同类型的SDS,表示len和alloc的类型不同,进而保存的SDS分配给字节数组的大小不同。
  • buf[]:字节数组,用来保存实际数据。不仅可以保存文本数据,还可以保存二进制数据。

Redis底层由C语言实现,那么SDS与C语言字符串对比:

  • O(1)获得字符串长度:因为SDS有len属性
  • 二进制安全:SDS不仅可以保存文本数据,还能保存二进制数据。SDS的使用len属性来判断是否遍历完成,不会管'\0'的字符
  • 不会发生缓冲区溢出:通过alloc-len来判断剩余空间大小,可以用来判断空间是否满足修改条件,如果不满足就会将SDS扩容。因此不会出现C语言的缓冲区溢出问题

扩容机制:

  • 如果所需的SDS长度小于1MB,则翻倍 + 1
  • 如果所需的SDS长度超过1MB,最后的扩容大小应该是newlen + 1MB + 1 

压缩列表

ZipList分为这几个部分:

  • zlbytes:整个压缩列表占用内存字节数
  • zltail:压缩表尾部节点距离起始地址多少个字节,也就是列表尾的便宜量
  • zllen:entry节点的个数
  • entry部分:存储数据的部分
  • zlend:压缩列表的结束点,固定在0xFF

entry的构成:

  • prevlen:前一个节点的长度,目的是实现从后往前遍历
  • encoding:记录当前节点实际的类型和长度,类型主要是字符串和整数
  • data:记录当前节点的实际存储数据,类型和长度由encoding决定

prevlen属性的大小:

  • 如果前一个节点的长度小于254字节,那么prevlen属性需要1字节
  • 如果前一个节点的长度大于等于254字节,那么prevlen属性需要5字节

encoding属性的大小:

  • 如果当前数据是整数,需要1字节
  • 如果当前的数据是字符串,会根据需要使用1、2、5字节的空间

连续更新问题:

  • 压缩列表新增某一个元素或者修改某一个元素,如果空间不够,压缩列表占用的内存空间需要重新分配。当更新的元素较大,会导致后续的prevlen也都要重新分配,从而引起连锁更新的问题

quicklist

在 Redis 3.0 之前,List 对象的底层数据结构是双向链表或者压缩列表。然后在 Redis 3.2 的时候,List 对象的底层改由 quicklist 数据结构实现。

quicklist就是双向链表+压缩列表的组合,quicklist链表中的每一个节点是一个压缩列表。

解决连锁更新:

  • 通过控制链表节点中的压缩列表的大小或者元素个数,来规避连锁更新的问题。因为压缩列表元素越小,连锁更新带来的影响就越小,从而性能提升

哈希表

dictht有这几个属性:

  • dictEntry **table:数组的每一个元素是指向哈希表节点的指针
  • size:哈希表大小
  • sizemask:掩码,用于计算索引值
  • used:哈希表已有的entry个数

哈希冲突:
当两个key不同,但是索引值相同,就会发生冲突

解决办法是采用拉链法:

  • 被分配到同一个哈希桶上的多个节点用一个单项链表连接起来
  • 但是也有缺点,当链表长度过长的时候,查询效率很低。

解决办法是rehash,分为三步:

  1. 给哈希表2分配空间,一般比哈希表1大一倍
  2. 将哈希表1数据迁移到哈希表2
  3. 迁移完成后,哈希表1的空间释放,并把哈希表2设置为哈希表1,然后在新哈希表2创建出一个空白的哈希表,为下次rehash做准备

 但是也有问题,迁移的过程很耗时间,因此采用了渐进式rehash:

  1. 给哈希表2分配空间,一般比哈希表1大一倍
  2. 在rehash期间,每次哈希表元素新增、删除、查找的时候,Redis会执行对应的操作外,还会将哈希表1中索引位置上的所有dictEntry迁移到哈希表2
  3. 迁移完成后,哈希表1的空间释放,并把哈希表2设置为哈希表1,然后在新哈希表2创建出一个空白的哈希表,为下次rehash做准备

rehash触发条件:

  • 负载因子 = 哈希表已保存的节点数量 / 哈希表大小
  • 当负载因子大于等于1,并且redis没有进行RDB快照和AOF重写的时候,进行rehash
  • 当负载因子大于等于5,说明哈希冲突非常严重,不管也没用RDB快照和AOF重写,都会强制执行rehash

整数集合

intset有这几个属性:

  • encoding:编码方式,比如 INTSET_ENC_INT16,那么contents就是一个int16_t类型的数组
  • length:集合包含的元素数量
  • contents:虽然被声明为 int8_t 类型,但是实际上是由保存的数据大小由encoding决定

升级规则:

  • 当我们将一个新元素加入集合中,如果新元素的类型(int32_t)比现有元素的类型(int16_t)都要长,需要扩宽contents数组的大小。
  • 在原本的数组上,将每个元素按间隔类型分割,比如如果encoding属性值为INTSET_ENC_INT16,那么间隔就是16位。
  • 比如现在有3个类型为int16_t的元素,每个都是16位长度,然后往整数集合里面加入一个新元素65535,这个新元素类型用int32_t保存,然后对contents扩容,会在原本的空间的大小之上多出80位(4 * 32 - 3 * 16 = 80),这样就能保证可以存下4个int32_t的元素
  • 然后从后往前依次填充,最终再把65535这个元素放到最后。

整数集合升级的好处:

  • 如果让一个数组保存int16_t、int32_t、int64_t的元素,最好的方式就是用int64_t类型,但是会造成空间的浪费。
  • 整数升级保证了我们只需要int64_t类型的元素再进行扩容,因此可以节约资源内存
  • 另外,整数集合不支持降级 

跳表

跳表是在链表的基础上改进过来的,是一个多层有序链表。

跳表zskiplist有以下属性:

  • 跳表的头尾节点head,tail
  • 跳表的长度length
  • 跳表的最大层数level

跳表节点zskiplistNode有以下几个属性:

  • ele:SDS结构存储数据
  • score:节点的分数,浮点型
  • backward:指向上一个节点的回退指针,支持从表尾向表头遍历,也就是ZREVRANGE命令
  • level:是个zskiplistLevel数组,zskiplistLevel包含了两个字段,一个是forward,指向下一层能调到哪个节点,span记录了距离下个节点的步数。数据结构就表示每个节点是个多层结构

跳表节点层数设置:

  • 跳表的相邻两层的节点数量最理想的比例是 2:1,查找复杂度可以降低到 O(logN)。 
  • Redis在创建节点的时候,会生成范围为[0, 1]的随机数,如果这个随机数小于0.25(相当于概率25%),那么层数就增加一层。然后继续生成下一个随机数,直到随机数的结构大于0.25就结束
  • 这样的做法,相当于每增加一层的概率不超过 25%,层数越高,概率越低,层高最大限制是 64。

为什么用跳表而不用平衡树? 

  • 从内存占用上,跳表比平衡树更灵活:平衡树每个节点包含2个指针,跳表每个节点包含的指针数目为1/(1-p),在redis中p=0.25,平均每个节点包含1.33个指针,内存占用更少
  • 在做范围查询的时候,跳表比平衡树操作更简单:在平衡树中我们找到特定范围的最小值后,还需要以中序遍历的顺序寻找其他不超过大值的节点,所以中序遍历不容易实现。而跳表就很简单,只需要找到最小值后,对第一层的节点进行若干步的遍历即可
  • 在算法实现难度上,跳表更简单。平衡树的插入和删除操作可能引发子树的调整,子树逻辑复杂。而跳表的插入和删除只需要修改相邻的节点,操作简单又迅速。

listpack

quicklist并没有完全解决连锁更新问题,因为quicklist还是使用了压缩列表来保存元素,于是有了listpack

listpack结构:

  • listpack头包含两个属性,分别记录了listpack总字节数和元素数量。然后listpack也有一个结尾标识。listpack entry是listpack的节点

listpack entry:

  • encoding:定于元素的编码类型,会对不同长度的整数和字符串进行编码
  • data:实际存放的数据
  • len:encdong+data的总长度

将prevlen改成len之后能不能从后往前遍历?

  • 答案是可以。lpDecodeBacklen函数已经实现了 

Redis数据对象有哪些

概述

常见的对象有以下五种:

  • String:二进制安全的,特性是可以包含任何数据比如一个序列化的对象,一个键最大能存储512M。适用于简短的字符场景。底层数据结构采用的是SDS或者INT编码
  • Hash:键值对数据结构,相当于编程语言的Map。适用于存储、读取、修改用户属性。底层数据结构是哈希表或者压缩列表
  • Set:包含字符串的无序集合,增删查找快。使用于最新消息排行榜,消息队列。底层数据结构是哈希表或者整数集合
  • Sort Set: 将Set集合加一个权重参数score,元素按照score排序。特性是在插入元素的时候自然排序。适用于排行榜、带权重的消息队列。底层数据结构是跳表或者压缩列表

String

字符串对象的内部编码(encoding)有 3 种 :int、raw和 embstr。

  • int:如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型表示,那么这个字符串对象会被保存在redisObject对象的prt中,同时将encoding设置成int
  • embstr:如果一个字符串对象保存的是字符串,并且这个字符串对象小于等于32字节。那么字符串对象将用SDS表示,同时encoding设置成embstr
  • raw:如果一个字符串对象保存的是字符串,并且这个字符串对象大于32字节。那么字符串对象将用SDS表示,同时encoding设置成raw

embstr和raw都会用SDS来保存值,但不同之处在于embstr会通过一次内存分配函数来分配一块连续的内存空间来保存redisObject和SDS。而raw编码会调用两次内存分配函数分别分配redisObject和SDS。

embstr相比raw好处:

  • embstr编码创建字符串对象只用调用一次内存分配函数,而raw编码需要两次
  • 释放embstr编码的字符串对象同样也只需要调用一次内存释放函数
  • 因为embstr编码的字符串对象的所有数据都保存在一块连续的内存空间,可以更好的利用cpu缓存提升性能

但embstr也有缺点:

  • 如果字符串的长度需要重新分配空间时,整个redisObject和sds都需要重新分配空间,所以embstr编码的字符串对象实际上是只读的。redis没有为embstr编码的字符串对象编写任何修改的程序。当我们对embstr编码的字符串对象执行修改的命令,实际上是先将编码从embstr转换成raw,再做修改。 

List

底层是双向链表和压缩列表

  • 如果列表中的元素小于512个,列表每个元素的值都小于64字节,redis会用压缩列表存储
  • 否则用双向链表

在redis3.2之后,使用quicklist作为底层数据结构

Hash

  • 如果哈希类型元素个数小于512个,并且所有值小于64字节,Redis会用压缩列表底层数据结构 
  • 否则用哈希表

 在redis7.0,压缩列表结构被抛弃,使用listpack

Set

  • 如果集合中的元素都是整数且元素个数小于512使用整数集合
  • 否则用哈希表

Zset

  • 如果有序集合元素小于128个,并且每个元素大小小于64字节,使用压缩列表
  • 否则用跳表

Redis7.0已经将压缩列表废弃使用listpack 

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

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

相关文章

Gale-Shapley算法

一. 设计目的 盖尔-沙普利算法(Gale-Shapley算法)的设计目的是为了解决稳定匹配问题,即在给定一组男性和女性的偏好列表的情况下,找到一个稳定的匹配。这里的“稳定”指的是不存在任何一对男性和女性,他们彼此都比当前…

JWT令牌与微服务

1. 什么是JWT JWT(JSON Web Token)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于作为JSON对象在各方之间安全地传输信息。JWT通常用于身份验证和信息交换。 以下是JWT的一些关键特性: 紧凑&#xff…

视频点播系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️:架构: B/S、MVC 2⃣️:系统环境:Windowsh/Mac 3⃣️:开发环境:IDEA、JDK1.8、Maven、Mysql5.7 4⃣️:技术栈:Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…

docker部署Melody开源音乐管理工具

Melody是一款非常实用的开源音乐管理工具。它不仅功能强大、操作简便,还支持多平台检索和一键下载/上传功能。更重要的是,它还支持一键“解锁”无法播放的歌曲和多端适配。如果你也是音乐爱好者,不妨试试Melody,让你的音乐生活更加…

问题小记-达梦数据库报错“字符串转换出错”处理

最近遇到一个达梦数据库报错“-6111: 字符串转换出错”的问题,这个问题主要是涉及到一条sql语句的执行,在此分享下这个报错的处理过程。 问题表现为:一样的表结构和数据,执行相同的SQL,在Oracle数据库中执行正常&…

day4:tomcat—maven-jdk

一,java项目部署过程 编译:使用javac命令将.java源文件编译成.class宇节码文件打包:使用工具如maven或Gradle将项目的依赖、资源和编译后的字节码打包成一个分发格式,如.jar文件,或者.war文件(用于web应用&#xff09…

【D3.js in Action 3 精译_046】DIY 实战:在 Observable 平台利用饼图布局函数实现 D3 多个环形图的绘制

当前内容所在位置: 第五章 饼图布局与堆叠布局 ✔️ 5.1 饼图和环形图的创建 ✔️ 5.1.1 准备阶段(一)5.1.2 饼图布局生成器(二)5.1.3 圆弧的绘制(三)5.1.4 数据标签的添加(四&#…

Swin transformer 论文阅读记录 代码分析

该篇文章,是我解析 Swin transformer 论文原理(结合pytorch版本代码)所记,图片来源于源paper或其他相应博客。 代码也非原始代码,而是从代码里摘出来的片段,配上简单数据,以便理解。 当然&…

Vscode搭建C语言多文件开发环境

一、文章内容简介 本文介绍了 “Vscode搭建C语言多文件开发环境”需要用到的软件,以及vscode必备插件,最后多文件编译时tasks.json文件和launch.json文件的配置。即目录顺序。由于内容较多,建议大家在阅读时使用电脑阅读,按照目录…

麒麟操作系统服务架构保姆级教程(二)sersync、lsync备份和NFS持久化存储

如果你想拥有你从未拥有过的东西,那么你必须去做你从未做过的事情 上篇文章我们说到rsync虽好,但是缺乏实时性,在实际应用中,咱们可以将rsync写进脚本,然后写进定时任务去备份,如果每天凌晨1:00…

关于小程序内嵌h5打开新的小程序

关于小程序内嵌h5打开新的小程序 三种方式 https://juejin.cn/post/7055551463489011749 只依赖于h5本身的就是 https://huaweicloud.csdn.net/64f97ebb6b896f66024ca16c.html https://juejin.cn/post/7055551463489011749 navigateToMiniProgram 故小程序webview里的h5无法…

QP:Query切词

Query 分词(切词) 分词指将一段连续的文本切成一个个独立且有意义的词汇,在文本召回中会对 Doc 文本内容分词以构建索引,并通过对查询词 Query 分词后去做检索。Query 分词在搜索中是一个基础信号,除了文本召回&#…

鸿蒙元服务从0到上架【第二篇】

第一招:在AppGallery后台下载对应的证书等文件 AppGallery后台 新增发布证书,具体操作可查看申请发布证书 申请发布Profile证书 第二招:在IDE中填写 第三招:打包【⚠️发布上架的只能是Build App】 终端展示这一片绿&#xf…

9_HTML5 SVG (5) --[HTML5 API 学习之旅]

SVG 模糊效果 HTML5中的SVG&#xff08;可缩放矢量图形&#xff09;允许我们创建高质量的二维图形&#xff0c;包括应用各种滤镜效果。模糊效果是通过<feGaussianBlur>滤镜原语来实现的。下面我将给出4个使用SVG进行模糊效果处理的示例&#xff0c;并为每个代码段添加详…

vue+node+mysql8.0,详细步骤及报错解决方案

1.下载需要安装的插件 下载express npm install express下载cors&#xff0c;用于处理接口跨域问题 npm install cors下载mysql npm install mysql 2.配置服务器 可以在vue项目的src同级创建server文件夹&#xff08;这里的位置可随意选择&#xff09; 然后依次创建&#…

相机雷达外参标定综述“Automatic targetless LiDAR–camera calibration: a survey“

相机雷达外参标定综述--Automatic targetless LiDAR–camera calibration: a survey 前言1 Introduction2 Background3 Automatic targetless LiDAR–camera calibration3.1 Information theory based method(信息论方法)3.1.1 Pairs of point cloud and image attributes(属性…

Epic游戏使用mod

以土豆兄弟为例&#xff1a; 第一步&#xff1a;获取 SteamCMD 下载官方 Steam 控制台客户端 (steamCMD) 1. 下载好后打开&#xff0c;是一个在 cmd 窗口的运行的命令行 2. 输入以下代码登录 login anonymous 第二步&#xff1a; 确认自己要下载的游戏 ID 和 mod ID 然后…

EGO Swarm翻译

目录 摘要 Ⅰ 介绍 Ⅱ 相关工作 A . 单四旋翼局部规划 B . 拓扑规划 C. 分布式无人机集群 Ⅲ 基于梯度的局部规划隐式拓扑轨迹生成 A.无需ESDF梯度的局部路径规划 B.隐式拓扑轨迹生成 Ⅳ 无人机集群导航 A 机间避碰 B. 定位漂移补偿 C. 从深度图像中去除agent Ⅴ …

FFmpeg 框架简介和文件解复用

文章目录 ffmpeg框架简介libavformat库libavcodec库libavdevice库 复用&#xff08;muxers&#xff09;和解复用&#xff08;demuxers&#xff09;容器格式FLVScript Tag Data结构&#xff08;脚本类型、帧类型&#xff09;Audio Tag Data结构&#xff08;音频Tag&#xff09;V…

基于LSTM长短期记忆神经网络的多分类预测【MATLAB】

在深度学习中&#xff0c;长短期记忆网络&#xff08;LSTM, Long Short-Term Memory&#xff09;是一种强大的循环神经网络&#xff08;RNN&#xff09;变体&#xff0c;专门为解决序列数据中的长距离依赖问题而设计。LSTM因其强大的记忆能力&#xff0c;广泛应用于自然语言处理…