Redis底层数据结构(详细篇)

news2024/11/17 23:36:56

Redis底层数据结构

  • 一、常见数据结构的底层数据结构
    • 1、动态字符串SDS(Simple Dynamic String)
      • 组成
    • 2、IntSet
      • 组成
      • 如何保证动态
      • 如何确保有序呢? 底层如何查找的呢?
    • 3、Dict(dictionary)
      • 3.1组成
      • 3.2 扩容
      • 3.3 收缩
      • 3.4 rehash
    • 4、ZipList
      • 连锁更新问题
      • 总结特性
    • 5、 QuickList
      • 5.1 组成
      • 5.2 底层源码(结合组成示意图理解)
      • 5.3 特点总结
    • 6、SkipList
      • 它和其他传统链表不同:1、元素按升序排列(也是方便后续的查找)
      • 2、节点可能包含多个指针,跨度不一样(加速查找效率,跳表的来源)
      • 特点总结:
    • 最后:redis的对象(redisObject)
      • 逐层分析
        • 1、type
        • 2、encoding
        • 3、lru(最后一次使用时间)
        • 4、refcount
        • 5、ptr(指针)
  • 二、常见数据结构
    • 1、String
    • 2、LIST
    • 3、Set(无序唯一)
    • 4、ZSet(SortedSet)
    • 5、Hash

一、常见数据结构的底层数据结构

1、动态字符串SDS(Simple Dynamic String)

在这里插入图片描述

组成

字符数组存储数据,头部存储字符数量,预分配内存,SDS类型(5个字节已被弃用)。
问题来了:为什么要这样设计呢?为什么不用c语言的字符串呢?
回答

  • 1、保证二进制安全 2、无需遍历数组获取长度
    其实c语言没有字符串,是靠字符数组实现的,并且以“ \0 ”作为结束标志,但是如果数据中间存在结束字符会导致读取数据不全的问题,所以引入len变量来保存字符数量,以len作为标准去读取数据,同时无需遍历数组获取长度(len)。
  • 3、动态扩容
    在这里插入图片描述
    预分配有啥好处嘛?
    在操作系统中,分配内存需要内核态和用户态的转换,该过程十分损耗性能,所以当大于1m,会分配多1m,防止多次分配带来的性能损耗。

2、IntSet

组成

本质是一个动态有序的整数数组。
在这里插入图片描述
encoding表示编码方式,数组中的数据就按照该编码方式存储。

如何保证动态

问题来了:如果数据超过了编码的范围怎么办呢?
在这里插入图片描述
在这里插入图片描述
回答: 我们通过编码升级,倒叙依次拷贝(防止正序覆盖当前数据),再添加新元素,最后头信息:length+1并且编码修改为对应的编码类型。

如何确保有序呢? 底层如何查找的呢?

在这里插入图片描述
本质就是二分查找,找到则不插入返回错误,没找到则插入有序的适当位置。

3、Dict(dictionary)

3.1组成

和java中jdk1.7版本的HashMap底层数据结构十分相似,由三部分组成:hash表(数组),哈希节点(entry)、字典(Dict)
在这里插入图片描述
每个Dict有两个hashTable一个用于存储当前数据,一个用于rehash(后续详细介绍)。
每个hashTable(dictHT)存储entry的指针以及hash表大小和entry个数,其中有一个sizemask用于进行hash求索引比如n&sizemask等价于n%size(sizemask+1),&运算速率更加快。
当发生hash碰撞的时候就是key运算后索引相同则使用单向链表,进行前插法添加新元素。
在这里插入图片描述

3.2 扩容

在这里插入图片描述

3.3 收缩

hashTable默认size为4,怎么收缩都不能低于4。
收缩后的size为大于等于实际entry个数的最小2的n次方(5->8)
在这里插入图片描述

3.4 rehash

在这里插入图片描述
因为一次新增的数据太多,导致rehash一次性更新到新的hashTable时长太长而影响其他业务性能,所以每次执行增删改查的时候才会去更新一个索引的数据,直到结束为止。

4、ZipList

在这里插入图片描述
为什么不使用相同内存存储entry呢?
回答:之所以叫压缩列表,就是因为去除了链表中的指针(一个指针8字节),并且每个entry由实际内容决定,节省了大批内存空间。
在这里插入图片描述
在遍历的时候,无需使用链表的指针来获取前一个元素和下一个元素,而是根据previous_enrty_length计算前一个entry的起始地址,通过自身大小计算下一节点地址。
在这里插入图片描述
在这里插入图片描述

连锁更新问题

在这里插入图片描述
如果这个时候插入一个节点并且长度大于254,将会导致pre_enrty_length属性由1字节变成5字节导致后面的该属性全部连锁更新为5字节。
(该情况发生概率很低)
在这里插入图片描述

总结特性

  • 可以看成一种连续空间的"双向链表" ,首尾操作简单
  • 节点之间不通过指针连接,记录上一节点和本节点长度寻址,节省内存
  • 如果节点数量过多,导致链表过长,需要逐个遍历,查询效率不高
  • 增删大数据时可能发生连续更新问题

5、 QuickList

上面说到ZipList的致命缺点:空间连续,如果数据过多,申请效率会变低,查询效率也下降,如何解决呢?

  • 可以通过限制ZipList的长度和entry大小
  • 对于大量的数据进行分片,多个ZipList存储
  • 多个ZipList进行联系,引入主角:QuickList

5.1 组成

QuickList本质是一个双端链表,但是每个节点指向ZipList,使得ZipList们联系起来。
在这里插入图片描述

config get list-max-ziplist-size 

在这里插入图片描述
在这里插入图片描述

config get list-compress-depth 

在这里插入图片描述

5.2 底层源码(结合组成示意图理解)

在这里插入图片描述

5.3 特点总结

  • 是一个节点为ZipList的双端链表
  • 节点采用ZipList,解决了传统链表的内存占用问题(指针)
  • 控制了ZipList的大小,解决申请效率的问题
  • 中间节点可以进一步压缩,进一步节省内存空间。

6、SkipList

上面聊了这么多链表,其实都没看到怎么去解决快速查找中间节点的问题,这里引入的SkipList就优化了链表中元素查找效率。

它和其他传统链表不同:1、元素按升序排列(也是方便后续的查找)

根据score值进行排序

2、节点可能包含多个指针,跨度不一样(加速查找效率,跳表的来源)

上源码:是个双向链表,每个节点值是SDS,整个排序考score,然后就是前后指针,由于增序,所以多级指针体现在forword(向后),跨度不一所以使用数组存储。
在这里插入图片描述
示意图
在这里插入图片描述

特点总结:

  • 双向链表,每个节点都含score和ele值
  • 节点按score排序,score值相同则按 ele字典排序(字符串)
  • 每个节点可包含多级指针,1-32之间
  • 指针层级越高,跨度越大
  • 增删修改效率和红黑树 基本一致,实现却简单

最后:redis的对象(redisObject)

在这里插入图片描述

逐层分析

1、type

就是我们熟悉的5中常见类型string 、hash、list、set和zset(4个bit)

2、encoding

就是五种类型在数据量不同的情况下不同的编码方式(4个bit)
在这里插入图片描述
在这里插入图片描述

3、lru(最后一次使用时间)

便于统计使用情况,用于统计空闲时间。(24bit)

4、refcount

引用计数器,便于淘汰和回收。

5、ptr(指针)

指向真正的数据。

其实这里就可以发现: 如果我们一直使用string类型去存储大量数据,会浪费很多对象的头内存,我们可以将其使用集合去存储进行内存的优化。

二、常见数据结构

1、String

使用的编码格式有三种 RAW EMBSTR INT

  • 基本的编码方式是raw,基于SDS(动态字符串),存储上限为512mb。
  • 如果存储的SDS长度小于等于44字节,则采用EMBSTR 编码,此时redisobj head和SDS是一段连续空间。申请内存时只需要调用一次内存分配函数(设计到内核态和用户态的切换),效率更高。
  • 如果存储的字符串是整数,并且大小在LONG_max范围内,则采用INT编码,直接使用pre指针位置(刚好8字节),不需要SDS。
    在这里插入图片描述

2、LIST

  • 在3.2版本之前,Redis采用ZipList和Linklist来实现List,当元素小于512并且元素大小小于64字节时采用ZipList编码,超过采用Linklist。
  • 3.2之后,统一使用QuickList来实现。
    具体QuickList请看上述中的详解。

3、Set(无序唯一)

  • 为了查询效率和唯一性,set采用HT编码(Dict)。Dict中的key用来存储元素,value统一为null。
  • 当存储的数据都是整数的时候,并且元素数量不超过set-max-intset-entries时,set采用IntSet编码,以节省空间。
    如图 当元素为{5,10,20}这时候 sadd s1 m1 会将编码方式由intset转为dict。

在这里插入图片描述

4、ZSet(SortedSet)

其中的每一个元素都需要指定一个score值和member值:

  • 根据score值排序
  • member值唯一(set都是这样的)
  • 根据member查询score
    so:底层数据结构必须满足 键值存储,键唯一,可排序
  • dict 满足键值存储和根据key找value
  • skipList 满足可排序,可以存储score和member
    其实底层就是综合了他们的优点来满足需求,二者都要,一共两份数据(空间换时间)。
    示意图:
    在这里插入图片描述
    key存ele ,value存score实现ele找score ,但是根据score排序。

大家可以看到当元素少的时候其实性价比不高,内存消耗比较大,所以
当元素不多的时候,底层会采用zipList实现存储。
什么叫不多?界限是啥? 同时满足以下两个条件(一般都是个数,内存大小)

  • 元素小于128(默认)可以调节。
  • 每个元素小于64字节

学了zipList知道其实他本身不具备 键值存储,键唯一,可排序三个特点如何实现呢?

  • zipList是连续空间,因此score和ele紧挨着一起的两个enrty,ele在前。
  • score越小越接近队首,按score升序排列。
    在这里插入图片描述

5、Hash

其实学了zset,发现二者很相似,只不过hash不需要保证有序,所以立马知道,其底层就是dict,但是当数据量不多则使用zipList。
hash默认是使用zipList编码,节省空间,相邻两个entry存的就是key 和value。
当数据量大时则转为HT(dict)编码,触发条件有两个:

  • 元素数量超过512(默认,可调节)
  • 大小超过64字节(默认,可调节)
    在这里插入图片描述
    以上则是Redis底层主要的数据结构。

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

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

相关文章

论文阅读《Robust Steganography for High Quality Images》高质量因子图片的鲁棒隐写

TCSVT 2023 中国科学技术大学 Kai Zeng, Kejiang Chen*, Weiming Zhang, Yaofei Wang, Nenghai Yu, "Robust Steganography for High Quality Images," in IEEE Transactions on Circuits and Systems for Video Technology, doi: 10.1109/TCSVT.2023.3250750. 一、…

三方共建 | 网络安全运营中心正式揭牌成立

9月3日,广州迎来了一场网络安全领域的盛事。悦学科技、聚铭网络、微步在线联合打造的7x24小时网络安全运营中心(以下简称“中心”)正式成立,并在现场举行了庄重而热烈的揭牌仪式。众多行业专家、企业代表齐聚一堂,共同…

【C++ Primer Plus习题】16.2

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include <string> #inc…

【Python决策树】ID3方法建立决策树为字典格式,并调用 treelib 显示

首先&#xff0c;我们使用 treelib 库来显示树结构 : ps : 如果 treelib 输出一堆乱码, 可以点进Tree修改 tree.py 大概 930 行左右的部分(去掉encode就行了) if stdout:print(self._reader) # print(self._reader.encode("utf-8"))else:return self._reader将字典…

基于Python的B站热门视频可视化分析与挖掘系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 随着互联网视频平台的迅猛发展&#xff0c;如何从海量的数据中提炼出有价值的信息成为了内容创作者们关注的重点之一。B站&#xff08;哔哩哔哩&#xff09;作为国内领先的年轻人文化社区&#xf…

应用层协议 —— https

目录 http的缺点 https 安全与加密 运营商挟持 常见的加密方式 对称加密 非对称加密 数据摘要&#xff08;数据指纹&#xff09; 不安全加密策略 1 只使用对称加密 2 只使用非对称加密 3 双方都是用非对称加密 4 对称加密和非对称加密 解决方案 CA证书 http的缺点 我们可…

基于鸿蒙API10的RTSP播放器(八:音量和亮度调节功能的整合)

一、前言&#xff1a; 笔者在前面第六、七节文章当中&#xff0c;分别指出了音量和屏幕亮度的前置知识&#xff0c;在本节当中&#xff0c;我们将一并实现这两个功能&#xff0c;从而接续第五节内容。本文的逻辑分三大部分&#xff0c;先说用到的变量&#xff0c;再说界面&…

智慧环保平台建设方案

智慧环保平台建设方案摘要 政策导向与建设背景 背景&#xff1a;全国生态环境保护大会提出坚决打好污染防治攻坚战&#xff0c;推动生态文明建设&#xff0c;目标是在2035年实现生态环境质量根本好转。构建生态文明体系&#xff0c;包括生态文化、生态经济、目标责任、生态文明…

表格标记<table>

一.表格标记、 1table&#xff1a;表格标记 2.caption:表单标题标记 3.tr:表格行标记 4.td:表格中数据单元格标记 5.th:标题单元格 table标记是表格中最外层标记&#xff0c;tr表示表格中的行标记&#xff0c;一对<tr>表示表格中的一行&#xff0c;在<tr>中可…

Excel数据转置|Excel数据旋转90°

Excel数据转置|Excel数据旋转90 将需要转置的数据复制在旁边空格处点击鼠标右键&#xff0c;选择图中转置按钮&#xff0c;即可完成数据的转置。&#xff01;&#xff01;&#xff01;&#xff01;非常有用啊啊啊&#xff01;&#xff01;&#xff01;

嵌入式Linux学习笔记(2)-C语言编译过程

c语言的编译分为4个过程&#xff0c;分别是预处理&#xff0c;编译&#xff0c;汇编&#xff0c;链接。 一、预处理 预处理是c语言编译的第一个阶段&#xff0c;该任务主要由预处理器完成。预处理器会根据预处理指令对源代码进行处理&#xff0c;将预处理指令替换为相应的内容…

游戏各个知识小点汇总

抗锯齿原理记录 SSAA&#xff1a;把成像的图片放大N倍&#xff0c;然后每N个点进行平均值计算。一般N为2的倍数。比如原始尺寸是1000x1000&#xff0c;长宽各放大2倍变成2000x2000。 举例&#xff1a; 原始尺寸&#xff1a; 放大2倍后 最后平均值计算成像&#xff1a; MSAA&…

基于SpringBoot+Vue的网上蛋糕销售系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

踩坑记:Poco库,MySql,解析大文本的bug

这两天在调试一个小功能&#xff0c;使用c,读取MySql。使用的是Poco库。按照官网的写法&#xff1a; std::cout << "read normal data by poco recordset "<<std::endl;Poco::Data::MySQL::Connector::registerConnector();Poco::Data::Session session(…

.NET 6.0 + WPF 使用 Prism 框架实现导航

合集 - .NET 基础知识(3) 1..NET 9 优化&#xff0c;抢先体验 C# 13 新特性08-202.《黑神话&#xff1a;悟空》神话再现&#xff0c;虚幻引擎与Unity/C#谁更强&#xff1f;08-21 3..NET 6.0 WPF 使用 Prism 框架实现导航09-11 收起 阅读目录 前言什么是Prism?安装 Prism使…

【卷起来】VUE3.0教程-09-整合Element-plus

最后一次课了&#xff0c;给个关注和赞呗 &#x1f332; 简介 Element Plus 是一个基于 Vue 3 的高质量 UI 组件库。它包含了丰富的组件和扩展功能&#xff0c;例如表格、表单、按钮、导航、通知等&#xff0c;让开发者能够快速构建高质量的 Web 应用。Element Plus 的设计理念…

洛谷 P4683 [IOI2008] Type Printer

原题点这里 题目来源于&#xff1a;洛谷 题目本质&#xff1a;深搜&#xff0c;字典树Trie 当时想法&#xff1a;当时看了题目标签&#xff0c;就有思路了&#xff08;见代码注释&#xff09;&#xff0c;但一直REWA最后只剩下RE。 正确思路&#xff1a; 我们使用字典树来完…

【机器学习】任务四:使用贝叶斯算法识别葡萄酒类别和使用三种不同的决策树方法(ID3,C4.5,CART)对鸢尾花数据进行分类

目录 1.基础知识 1.1 高斯贝叶斯&#xff08;Gaussian Naive Bayes&#xff09; 1.2 决策树&#xff08;Decision Tree&#xff09; 1.3 模型评价&#xff08;Model Evaluation&#xff09; 1.3.1 评价维度&#xff1a; 1.3.2 评价方法&#xff1a; 2.使用贝叶斯算法识别…

android 删除系统原有的debug.keystore,系统运行的时候,重新生成新的debug.keystore,来完成App的运行。

1、先上一个图&#xff1a;这个是keystore无效的原因 之前在安装这个旧版本android studio的时候呢&#xff0c;安装过一版最新的android studio&#xff0c;然后通过模拟器跑过测试的demo。 2、运行旧的项目到模拟器的时候&#xff0c;就报错了&#xff1a; Execution failed…

proteus+51单片机+AD/DA学习5

目录 1.DA转换原理 1.1基本概念 1.1.1DA的简介 1.1.2DA0832芯片 1.1.3PCF8591芯片 1.2代码 1.2.1DAC8053的代码 1.2.2PCF8951的代码 1.3仿真 1.3.1DAC0832的仿真 1.3.2PFC8951的仿真 2.AD转换原理 2.1AD的基本概念 2.1.1AD的简介 2.1.2ADC0809的介绍 2.1.3XPT2…