Redis中的数据结构与内部编码

 

  本篇文章主要是对 Redis 常见的数据结构进行讲解,同时还对其所对应的不同的内部编码进行讲解。希望本篇文章会对你有所帮助。

文章目录

一、五大数据结构

二、数据结构对应的编码方式

String

hash

list

set

zset


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:Redis 👀

💥 标题:Redis中的数据结构与内部编码 💥

 ❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️

  我们知道,redis是支持不同的数据类型的,而不同的数据类型底层所采用的数据结构也有所差异,同时不同的数据结构也会有不同的操作指令。我们这里所说的不同的数据类型都是指的value的类型,而key的类型固定是string的。上篇文章讲解到的type指令,其返回值是key所对应的value的数据类型!

一、五大数据结构

   Redis的键值对中,value所用到的五种主要的数据结构,它们分别是:

  1. String(字符串):最基本的类型,可以包含任何形式的数据,比如一个文本、JSON字符串或者二进制数据。

  2. List(列表):一个有序的字符串列表,元素的顺序由插入顺序决定,可以在两端进行插入和删除操作。

  3. Set(集合):一个不重复且无序的字符串集合,可对集合中的元素进行添加、删除和判断某个元素是否存在的操作。

  4. Hash(哈希表):类似于关联数组,包含字段和与其对应的值,常用于存储对象。

  5. Zset(有序集合):类似于集合,但每个元素都关联一个分数,可以按照分数进行排序,适合构建排行榜等功能。

  具体可看下图:

  

  Redis 底层在实现上述数据结构的时候,会在源码层面针对上述实现进行特定的优化,来达到节省时间或者节省空间的效果。简单来说,数据结构的内部具体实现不是固定统一的,会根据不同的情况,redis会自动适配合适的数据结构。但是每个数据结构的底层实现有固定的几种方式。

  举个例子,redis承诺现在我这有个hash表,你进行查询、插入、删除操作都保证O(1)的书简复杂度。但是这个背后的实现,不一定就是一个标准的hash表。可能再特定场景下,使用别的数据结构实现。但是仍然保证时间复杂度符合承诺。

  那么哦我们现在就会有两个大致方向上的理解:

  • 数据结构是指redis 承诺给你的。也可以理解成数据类型;
  • 编码方式是redis内部底层的实现;
  • 一个数据结构有对应固定的编码方式。

二、数据结构对应的编码方式

  实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现这样 Redis 会在合适的场景选择合适的内部编码。具体数据结构所对应的编码方式如下:

数据结构内部编码
string1.raw
2.embstr
3.int
hash1.hashtable
2.ziplist
list1.linkedlist
2.ziplist
set1.hashtable
2.intset
zset1.skiplist
2.ziplist

  下面我们来详细解释一下不同的内部编码。

String

  Redis中 String 的内部编码有三种:int、raw、embstr。

  1. int编码

    • 当字符串可以被解释为整数时,Redis会将该字符串以int编码进行存储,节省内存空间。
    • int编码使用64位有符号整数来表示,其范围为-2^63到2^63-1。
    • 当字符串的值处于int编码的范围内时,Redis会使用int编码来存储,这样可以减少内存占用并提高性能。
  2. raw编码

    • 当字符串无法被解释为整数时,Redis会以raw编码进行存储。
    • raw编码使用简单动态字符串(SDS)来表示,SDS是一种带有缓冲区的字符串表示形式,可以动态扩展和收缩,适用于存储任意长度的字符串数据。
    • raw编码适用于存储包含非整数数据的字符串,如文本、JSON、XML等。
  3. embstr编码

    • embstr是一种特殊的内部编码方式,用于存储长度较短的字符串。
    • 当字符串长度在一定范围内(默认为39字节)时,Redis会使用embstr编码来存储,以进一步减少内存开销。
    • embstr编码实际上将字符串值和其他元数据一起存储在一个连续的内存块中,节省了额外指针和分配内存的开销。

  SDS动态字符串可参考文章:Redis(设计与实现):01---数据结构之SDS动态字符串(raw、embstr、int、struct sdshdr)_sds类型的int与raw查询速度的区别

hash

  Redis 中的 Hash 类型可以使用两种内部编码方式:hashtable 和 ziplist。

  1. Hashtable:

    • Hashtable 是 Redis 中 Hash 类型的默认内部编码方式。
    • 当 Hash 中包含的键值对数量较多,或者键值对的值较大时,Redis 会自动将 Hash 内部编码为 Hashtable。
    • Hashtable 使用哈希表来存储键值对,可以快速进行数据查找,适合处理大规模的数据。
  2. Ziplist:

    • Ziplist 是一种紧凑的数据结构,适合存储小规模的数据。
    • 当 Hash 中包含的键值对数量较少,且每个键值对的键和值的长度都较小时,Redis 会选择使用 Ziplist 进行内部编码。
    • Ziplist 使用一段连续的内存空间来存储键值对,节约了内存的使用,但查找效率没有哈希表高。
    • 由于元素过少,通过遍历,时间复杂度还是可以认为是 O(1)

  总结来说,当 Hash 数据较大或者键值对较复杂时,Redis 会使用 Hashtable 进行内部编码以获得更好的性能;而当 Hash 数据较小且简单时,Redis 会选择使用 Ziplist 进行内部编码以节约内存空间。

  具体底层实现细节可参考文章:Redis(设计与实现):06---数据结构之压缩列表(ziplist、struct ziplist)_4位长,介于0至12之间的无符号整数Redis(设计与实现):03---数据结构之字典(hashtable、struct dictht、struct dictEntry、struct dict)-CSDN博客

list

  在 Redis 中,List 类型可以使用三种不同的内部编码方式:linkedlist、ziplist 和 quicklist。

  1. Linkedlist(双向链表):

    • linkedlist 内部编码主要适用于 List 包含的元素数量较多,或者元素的大小较大的情况。它通过指针将元素连接在一起,支持快速的插入和删除操作,适合处理大规模的数据。
  2. Ziplist(压缩列表):

    • ziplist 内部编码适用于 List 包含的元素数量较少,且每个元素的大小都比较小时。Ziplist 使用紧凑的数据结构来存储元素,节约了内存的使用,但查找和修改操作的效率没有 linkedlist 高。
  3. Quicklist(快速列表):

    • quicklist 是 Redis 为了优化 List 类型而引入的一种内部编码方式。它实际上是将多个 ziplist 连接在一起形成的一个双向链表结构。quicklist 既具备了 ziplist 节约内存空间的优点,又能够快速地处理大规模的数据,同时还兼顾了快速的插入和删除操作。

  综上所述,Redis 根据 List 中元素的数量和大小来选择合适的内部编码方式:linkedlist 适用于大规模数据的场景,ziplist 适用于节约内存的场景,而 quicklist 则是为了兼顾以上两种场景而设计的一种高效内部编码方式。大部分场景下都是使用的quicklist。

set

  在 Redis 中,Set 类型可以使用两种不同的内部编码方式:hashtable 和 intset。

  1. Hashtable(哈希表):

    • 当 Set 中的元素数量较多,或者元素较长时,Redis 会选择使用 hashtable 内部编码。这种编码方式使用了哈希表结构来存储元素,它提供了较快的查找、插入和删除操作,适用于处理较大规模的数据。
  2. Intset(整数集合):

    • 当 Set 中的所有元素都是整数,并且数量较少时,Redis 会选择使用 intset 内部编码。intset 使用紧凑的数组结构来存储整数元素,节省了内存空间的使用,并且提供了高效的操作,适用于存储小规模的整数数据集。

  在实际使用中,Redis 根据 Set 的特点(元素数量、元素类型等)来动态地选择合适的内部编码方式,以提高性能和节约内存空间。通过使用合适的内部编码方式,Redis 能够更好地满足不同场景下对 Set 数据类型的需求。

  intset底层实现可参考文章:Redis(设计与实现):04---数据结构之整数集合(intset、struct intset)

zset

  在 Redis 中,有序集合(Sorted Set)类型可以使用两种不同的内部编码方式:skiplist 和 ziplist。

  1. Skiplist(跳跃表):

    • 当有序集合中的成员数量较多或者成员较长时,Redis 会选择使用 skiplist 内部编码。跳跃表是一种基于链表的数据结构,它可以提供快速的插入、删除和查找操作。
    • Skiplist 编码方式适用于处理较大规模的有序集合数据,因为它能够保持较高的性能并且具有良好的平衡性能。
  2. Ziplist(压缩列表):

    • 当有序集合中的成员数量较少且每个成员都比较短小精悍时,Redis 会选择使用 ziplist 内部编码。压缩列表是一种紧凑的数据结构,可以节省内存空间,适用于存储较小规模的有序集合数据。
    • Ziplist 内部编码方式对于小型的有序集合数据具有较好的存储效率和操作性能。

  根据有序集合的实际情况,Redis 会动态地选择合适的内部编码方式,以便在不同场景下提供最佳的性能和内存利用率。

  skiplist底层实现原理可参考文章:Redis(设计与实现):05---数据结构之跳跃表(skiplist、struct zskiplistNode、struct zskiplist)_skiplist和zskiplistnode

  可以看到每种数据结构都有至少两种以上的内部编码实现,例如list数据结构包含了linkedlist和ziplist 两种内部编码。同时有些内部编码,例如ziplist,可以作为多种数据结构的内部实现,可以通过object encoding命令查询内部编码:

   Redis这样设计有两个好处:

  • 可以改进内部编码,而对外的数据结构和命令没有任何影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis 3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,而对用户来说基本无感知。
  • 多种内部编码实现可以在不同场景下发挥各自的优势,例如ziplist 比较节省内存,但是在列表元素比较多的情况下,性能会下降,这时候Redis 会根据配置选项将列表类型的内部实现转换为linkedlist,整个过程用户同样无感知。

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

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

相关文章

js 面试题学习笔记一

1、什么是防抖和节流?有什么区别?如何实现? 防抖:触发高频事件后N秒内函数只会执行一次,如果N秒高频事件再次被触发,则重新计算时间。(a时间触发,5秒内执行一次,但是第4…

10G UDP协议栈 (9)UDP模块

目录 一、UDP协议简单介绍 二、UDP功能实现 三、仿真 一、UDP协议简单介绍 UDP协议和TCP协议同位于传输层,介于网络层(IP)和应用层之间:UDP数据部分为应用层报文,而UDP报文在IP中承载。 UDP 报文格式相对于简单&am…

电脑出现:excel词典(xllex.dll)文件丢失或损坏的错误提示怎么办?有效的将丢失的xllex.dll修复

当遇到 Excel 提示“词典 (xllex.dll) 文件丢失或损坏”的问题时,通常意味着该动态链接库文件(Dynamic Link Library,DLL),它与拼写检查功能相关联的,无法被正确找到或者合适地使用。那么有什么办法可以解决…

LLVM技术在GaussDB等数据库中的应用

目录 LLVM和数据库 LLVM适用场景 LLVM对所有类型的SQL都会有收益吗? LLVM在OLTP中就一定没有收益吗? GaussDB中的LLVM 1. LLVM在华为应用于数据库的时间线 2. GaussDB LLVM实现简析 3. GaussDB LLVM支持加速的场景 支持LLVM的表达式&#xff1a…

vue项目出现多次ElMessage

问题: 解决方法: let message null if (message null) { message ElMessage.error(“登录过期,请重新登录”); } 最终效果:只出现一个弹框

Orange AIpro Color triangle帧率测试

OpenGL概述 OpenGL ES是KHRNOS Group推出的嵌入式加速3D图像标准,它是嵌入式平台上的专业图形程序接口,它是OpenGL的一个子集,旨在提供高效、轻量级的图形渲染功能。现推出的最新版本是OpenGL ES 3.2。OpenGL和OpenCV OpenCL不同,…

实操专区-第15周-课堂练习专区-漏斗图与金字塔图

实操专区-第15周-课堂练习专区-漏斗图 下载安装ECharts,完成如下样式图形。 代码和截图上传 基本要求:下图3选1,完成代码和截图 完成 3.1.3.16 漏斗图中的任务点 基本要求:2个选一个完成,多做1个加2分。 请用班级学号姓…

银行对公贷款软件业务流程详解

对公贷款业务是指商业银行向企事业单位提供资金支持,用于资本扩充、生产经营、项目建设等方面的融资。其目的在于支持企事业单位的发展,推动经济增长。通过提供资金支持,企事业单位可以获得必要的资金来扩大生产规模、提高生产能力、研发新产…

第8周 分布式事务与数据一致性主流解决方案落地

第8周 分布式事务与数据一致性主流解决方案落地 1. 最终一致性原理与解析2. 微服务的解耦3. 本地消息存储4. 自定义事务管理器5. 本地消息删除********************************************************************************** 本周拓展数据的一致性落地,采用弱…

【Java EE】网络原理——HTTP请求

目录 1.认识URL 2.认识“方法(method)” 2.1GET方法 2.1.1使用Fiddler观察GET请求 2.1.2 GET请求的特点 2.2 POST方法 2.2.1 使用FIddler观察POST方法 2.2.2 POST请求的特点 3.认识请求“报头”(header) 3.1 Host 3.2 C…

Spring MVC 工作流程源码分析

前言: 我们知道 Spring MVC 的核心是前端控制器 DispatcherServlet,客户端所有的请求都会交给 DispatcherServlet 来处理,本篇我我们来分析 Spring MVC 处理客户端请求的流程,也就是工作流程。 Sping MVC 只是储备传送门&#x…

Java整合EasyExcel实战——3(上下列相同合并单元格策略)

参考&#xff1a;https://juejin.cn/post/7322156759443095561?searchId202405262043517631094B7CCB463FDA06https://juejin.cn/post/7322156759443095561?searchId202405262043517631094B7CCB463FDA06 准备条件 依赖 <dependency><groupId>com.alibaba</gr…

邻接矩阵广度优先遍历

关于图的遍历实际上就两种 广度优先和深度优先&#xff0c;一般关于图的遍历都是基于邻接矩阵的&#xff0c;考试这些&#xff0c;用的也是邻接矩阵。 本篇文章先介绍广度优先遍历的原理&#xff0c;和代码实现 什么是图的广度优先遍历&#xff1f; 这其实和二叉树的层序遍…

新人学习笔记之(数组1)

一、数组的概念 1.数组&#xff08;Array&#xff09;可以把一组相关的数据一起存放&#xff0c;并提供方便的访问&#xff08;获取&#xff09;方式 2.数组是指一组数据的集合&#xff0c;其中的每个数据被称作元素&#xff0c;在数组中可以存放任意类型的元素&#xff0c;数组…

数据结构——二叉树的基本应用

在此之前我们已经初步了解了二叉树&#xff0c;在介绍堆的基本应用时&#xff0c;我们已经具体介绍了完全二叉树的基本应用&#xff0c;本章我们介绍二叉树的基本应用&#xff0c;这个不止指的是完全二叉树&#xff0c;而是指泛型的二叉树。 二叉树的基本应用&#xff0c;由于…

代码随想录算法训练营第54天|● 392.判断子序列 ● 115.不同的子序列

392. 判断子序列 这个微软面试的时候考过 双指针就行 编辑距离入门题&#xff1a; 思路是一样的 相同字符1 否则从前面顺下来 class Solution:def isSubsequence(self, s: str, t: str) -> bool:dp[[0]*(len(t)1) for _ in range(len(s)1)]for i in range(1,len(s)1):f…

aspose-*的使用

文章目录 aspose-*一、依赖--maven二、需求1、word------>pdf2、doc------>docx2、xls------>xlsx aspose-* 一、依赖–maven 备注&#xff1a;第三方的jar包可以从资源中下载&#xff0c;有上传的 <!--aspose依赖--><dependency><groupId>aspose…

刷代码随想录有感(81):贪心算法——分发饼干

题干&#xff1a; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(s.begin(), s.end());int index s.size() - 1;int res 0;for(int i g.size() - 1; i > 0; i--){if(index >…

GitLab项目中添加用户,并设置其角色权限等

注意&#xff1a;创建用户(new user)&#xff0c;创建完用户然后再项目邀请用户&#xff0c;选择创建过的用户 一、以管理员身份登录GitLab的WebUI并创建用户 1>.使用管理员登录GitLab 使用管理员(root)用户登录成功后&#xff0c;点击如下图所示的小扳手&#xff0c;点击…

java 反射的用法

下面是一个简单的Java反射示例&#xff0c;演示了如何使用反射机制获取类的信息并调用其方法&#xff1a; import java.lang.reflect.Method;class MyClass {private String name;public void setName(String name) {this.name name;}public String getName() {return name;}…