reids设计与实现(一)——数据结构

news2025/1/15 20:47:10

文章目录

    • 1. 前言
    • 2. redis 动态字符串
      • 2.1. 字符串的数据结构:
      • 2.2. 剖析,length;
      • 2.3. 剖析,free;
      • 2.3. 使用c字符串函数;
    • 3. redis 链表
    • 4. 字典
    • 5. 跳跃表
    • 6. 整数set(intset)
      • 6.1. 升级(upgarde)
    • 7. 压缩列表(ziplist)
      • 7.1. 列表结构
      • 7.2. 压缩列表节点的构成
      • 7.3. 连锁更新

1. 前言

reids作为最常用的缓存数据库,深入了解,对于业务开发大有裨益,那么从这里开始,我们从《redis设计与实现》这本书,我们同最常用的字符串入手,了解redis的设计与思路。

2. redis 动态字符串

字符串作为redis最为核心,最为常用的数据类型,后面我们称sds,我们深入了解一下。

2.1. 字符串的数据结构:

在这里插入图片描述我们从数据结构入手,猜测字符串实现的功能和特性,我们可以发现,这里相比于c字符串多了两个属性。freelen

2.2. 剖析,length;

  1. 快速获取length :首先,leng最简单的效果便是可以直接获取redis字符串的长短,由于是直接获取属性,时间复杂度为O(1)。

  2. 二进制安全: 除了获取长度外,为了实现redis的sds可以存储任意数据的功能,sds通过length判断字符串是否到结尾,这和c字符串不同(‘/0’),因此可以存储任意二进制数据。

2.3. 剖析,free;

其实简单length之后发现基本功能都差不多了,那么这个free有什么作用呢?

  1. 预留free空间: 减少重新分配,在sds除了记录length之外,还会分配一倍length(1mb大小以内)的未使用空间,如果length在再次增加的情况下,不过增加的长度小于free,则不需要重新分配内存。

2.3. 使用c字符串函数;

redis虽然自行实现了字符串数据机构,但是还是在字符串末尾增加一个’/0’空字符,目的是为了使用c字符串的函数。

3. redis 链表

redis链表并没有非常奇特的地方,在redis链表中主要有两个数据结构。

  1. list 统计
    在这里插入图片描述
    这里包括list的一些概要信息和一些函数,目的是为了后面使用链表节点方便一点。
  2. listnode 节点。
    在这里插入图片描述

一般来说这个在学习数据结构中用的很多,一般情况下,只需要记录一个pre node便可以遍历整个链表。

redis链表为双向链表。并没有过于多的特殊。

4. 字典

字典又称为符号表,map,key-value。

  1. dictht(hash)表,属性包括,hash表数组,表大小,hash表大小掩码,已有节点数量。
    在这里插入图片描述

  2. dictEntry表数据,是key-value结构
    在这里插入图片描述

redis对于hash冲突的解决方案是链地址法,即如果冲突,在原来dictEntrt下面通过next链接冲突节点。

  1. 字典,hash的上层结构,和java中的hashMap功能类似。
    在这里插入图片描述
    dictType 可以指定不同低操作函数。
    ht 为两个hash表,另外一个用于备份。(在再hash时使用)

  2. hash算法: hash算法和普通的hash表别无二致,通话hash算法,hash(key)& mask把数组放到表里。

  3. hash冲突
    redis使用链地址发把键值对存储在链表之前解决冲突,这样的时间复杂度为O(1)。

  4. rehash
    当hash表空间不够的时候,一般需要再次hash,
    渐进式再hash,在渐进式 rehash 过程中,Redis 会同时保持旧的哈希表和新的哈希表。然后,在每次执行命令时,Redis 会从旧哈希表中移动一小批键值对到新哈希表,这个过程分散在多个操作中逐步完成。

具体条件为

  1. 当负载因子大于1且没在持久化(BGSAVE,BGREWRITEAOF)会进行再hash。
  2. 当负载因子大于3,目前在执行BGSAVE,BGREWRITEAOF)时,会进行再hash。
  3. 在负载因子小于0.1时,会进行收缩。
  1. BGSAVE 命令用于在后台创建 Redis 数据库的快照。当执行此命令时,Redis 会 fork 出一个子进程,子进程则将内存中的数据写入到磁盘上的一个 RDB 文件中。这个过程不会阻塞主 Redis 进程,所以 Redis 可以继续处理客户端请求。RDB(Redis DataBase)文件是一个压缩的二进制文件,表示某一时刻 Redis 数据库的完整快照
  2. BGREWRITEAOF 命令用于优化 AOF(Append Only File)文件的大小。Redis 的 AOF 持久化通过记录数据库的所有写操作到一个文件中来工作,这个文件随着操作的积累会不断增长。BGREWRITEAOF 命令会在后台创建一个当前数据的最小操作集,以此来重写 AOF 文件,这个过程同样不会阻塞主 Redis 进程。

5. 跳跃表

跳跃表几乎只用于有序集合。
在这里插入图片描述

  1. zskiplistNode: 这是跳跃表的节点结构定义。每个节点代表有序集合中的一个元素。
  2. zskiplistLevel: 这个结构体定义了跳跃表节点在不同层级的信息,每个节点可以有一个或多个层级(level)。
  • forward: 是一个指向同一层级的下一个节点的指针。在查找操作中,这个指针允许我们“跳过”一些节点,从而更快地在跳跃表中进行搜索。

  • span: 这是一个无符号整数,它记录了当前节点与通过 forward 指针所指向的下一个节点之间的跨度。在进行范围查询或者计算排名时,这个值非常有用,因为它可以快速计算出两个节点之间的间隔。
    backward: 这是一个指向当前节点前一个节点的指针,在双向遍历时使用。

  1. score: 这是一个双精度浮点数,用来保存节点的分数值。在有序集合中,元素是根据这个分数进行排序的,分数相同时则按照存储的对象(obj)来进行字典序比较。

  2. obj: 这是一个指向实际存储数据的指针,通常是一个字符串类型。在 Redis 中,这是指向 robj(Redis 对象)的指针,它可以存储字符串、列表、哈希表等不同类型的数据结构。

  3. level[]: 这是一个大小可变的数组,它的具体长度取决于节点所在的层数。这个数组存储每一层的 zskiplistLevel 结构体,允许节点在跳跃表的多个层级上存在。

可以通过zskiplist持有这些节点。
在这里插入图片描述
为什么要用跳跃表?

简单性:跳表的算法和代码实现相比平衡树要简单得多。对于平衡树,如 AVL
树或红黑树,它们的旋转操作逻辑复杂,难以编写且容易出错。跳表提供了一种容易理解和实现的高效有序数据结构。

效率:跳表的查找、插入和删除操作的平均时间复杂度都是 O(log n),与平衡树相当。

灵活性:跳表支持快速的顺序访问和有效的范围查询,这对于数据库索引来说是非常重要的。

并发性:跳表的数据结构更容易实现锁定机制,这使得在并发环境下的性能表现更好。由于节点的层次结构,跳表可以更容易地实现细粒度锁或无锁并发算法。

动态:跳表无需预先知道数据规模,它可以根据实际需要动态地进行扩展,这在不可预知数据量的实时系统中非常有用。

空间效率:虽然跳表的多层结构需要额外的空间来存储指针,但它的空间复杂度仍然是线性的(O(n)),而且在实践中这个额外空间的使用通常是可控的。

实践:在实际应用中,跳表往往能够提供与平衡树相似或有时候更优的性能表现,特别是在插入和删除操作频繁的场景中。

6. 整数set(intset)

整数集合是集合键的底层实现之一,当一个集合包含整数值元素,并且这个集合的元素数量不多时,redis就会使用整数集合作为集合键的底层实现。

在这里插入图片描述

  1. encoding: 整数类型位宽
    决定着整数是几位的。

  2. length: 集合中元素数量

  3. contents 元素集合
    元素集合仅仅手encoding影响。
    intset 主要支持三种整数编码类型:16 位、32 位和 64 位整数

6.1. 升级(upgarde)

整数集合一般默认会给于较小的整数类型,如16位。

不过当加入一个新的集合元素,数据类型大于整数位宽的话,会进行升级操作,以便存入新的较长的整数。

下面简述下升级步骤

  1. 根据新元素的类型,拓展数组空间的大小。
  2. 将原来元素全部转换成新的元素。
  3. 将新元素添加到数组中。

有序集合不支持降级。

思考一下为什么?

  1. 判断麻烦
    升级操作只需大于当前数据类型即可,降级操作需要所有元素小于更小一档数据类型的长度,难以判断。

7. 压缩列表(ziplist)

Redis 的压缩列表(ziplist)是一种为了节省内存而设计的紧凑数据结构,用于存储整数值、小字符串或者一些较小的聚合数据结构,如小哈希表、小列表等。压缩列表是 Redis 内部使用的一种序列化方式,它通过在一个连续的内存区域中紧密排列数据元素来减少内存占用。

7.1. 列表结构

在这里插入图片描述

  • zibytes:unit32_t 4字节:
    记录压缩列表占用的字节数,可用于内存重合重分配和计算zlend
  • zltail :unit32_t 4字节:
    记录压缩列表起始地址到压缩列表表尾节点
  • zllen : unit16_t 2字节:
    记录压缩列表中包含节点的数量
  • entry 列表节点
    列表中的节点
  • alend unit8_t 1字节 特殊值
    标记压缩列表末端

7.2. 压缩列表节点的构成

在这里插入图片描述

  1. previous_entry_length:
    这个属性用于快速遍历压缩列表时向前移动。它记录了前一个节点的长度,如果前一个节点的长度小于254字节,则该长度直接存储在这个属性中;如果长度大于或等于254字节,则这个属性会占用5个字节,第一个字节设置为0xFE(254),接下来的4个字节存储前一个节点的实际长度。

  2. encoding: 该属性定义了节点值的类型和存储格式。它既可以表示值是一个整数还是一个字符串,又可以指示具体的存储方式,比如整数值可以根据大小使用不同的编码来节省空间,字符串则可以根据长度使用不同的编码方式。

  3. content: 这是节点实际存储的数据,其格式和长度由编码属性确定。如果节点存储的是整数,则内容直接是这个整数的二进制表示。如果节点存储的是字符串,则内容就是字符串的实际字节序列。

7.3. 连锁更新

连锁更新是压缩列表对于节点内容发生增加操作的时候会造成连续更新的操作,如果造成连环式更新会造成非常巨大的性能消耗,虽然这种概率很低?

这种情况是如何发生的的呢?

  1. 增加内容
    当节点数据增加的时候,如果恰好增加后大于254字节,那么后面的previous_entry_length势必会增加。
  2. 最坏情况
    如果恰好,previous_entry_length增加加上4个字节的时候,也大254个字节,后面的节点也会进行调成,最坏的情况,所有的节点都要调整。
  3. 调整过程
    由于压缩列表中每个节点都仅仅压缩在一起,每个节点调整,会造成所有后置节点内存地址重分配。所以最坏的复杂度为O(N^2)

节点减少会造成连锁更新吗
不会!

  • 连锁更新是个费事费力的操作,若非增加必要则不一定会做。
  • 在减少更新的过程中,这种压缩的作用手机节省内存,这个操作往往不会立即发生。

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

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

相关文章

【C++ 】list 类

1. 标准库中的list类 list 类 的介绍: 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代 2. list与forward_list非常相似:最主要的不同在于forward_list是单链表 3. 与其他的序列式容器相比(a…

汇编语言(Assemble Language)学习笔记(更新中)

零.学习介绍和使用工具 【1】我们使用的教材是机械工业出版社的《32位汇编语言程序设计第二版》。 指导老师是福州大学的倪一涛老师。 这门课程教授的是Intel 80*86系列处理器的32位汇编。我们现在的处理器都兼容这个处理器。 这篇博客只是大二下汇编语言学习的总结&#xff…

城乡居民基本医疗信息管理系统|基于Springboot的城乡居民基本医疗信息管理系统设计与实现(源码+数据库+文档)

城乡居民基本医疗信息管理系统目录 目录 基于Springboot的城乡居民基本医疗信息管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、病例管理 2、医院资讯信息管理 3、医院资讯类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选…

第十四次CCF-CSP(第二题 买菜、第四题 再卖菜)

第十四次CCF-CSP 第二题 买菜 原题链接:3263. 买菜 - AcWing题库 思路分析 简单来说,就是给出两组区间的集合A,B 求出两集合中相交区间的部分的长度,注意若区间 [s,t] 是相交的,则长度为 t-s 。 思路一 因为数据量比较小&am…

传输层的UDP协议

1. UDP协议报文格式 1.1 16位端口号 UDP协议报文中,端口号占2个字节,包括 源端口号 和 目的端口号。 1.2 16位UDP长度 UDP报文长度为2个字节 ,即UDP数据报长度为0~65535,也就是64kb。 1.3 16位UDP检验和 数据在网络传输的…

Opencv4.5读取视频文件失败的原因

0. 写在前面 这篇短文是对上期编译的一个补充:Windows11OpenCV4.5Qt5.9.1安装教程_opencv4.5.4 windows11安装-CSDN博客 1. 问题现象 上篇博文是读取图片数据成功,结果今天做项目,测试视频文件和录像时,发现capture.isOpened()返…

ROS2组件component自定义实现

ROS2系列文章目录 ROS2中nav_msgs/msg/Path 数据含义及使用 ROS2中std_msgs/msg/Header 数据含义及使用 ROS中TF变换详解 ROS2中launch编写及参数含义(launch.xml、python) 提示:阅读并实践本文档后,将掌握并理解ros1中nodele…

Python面向对象析构函数你学会了吗?

​ 当我第一次接触Python面向对象编程时,我完全被析构函数的概念给搞懵了。但是,随着我深入研究,我发现它其实并没有那么复杂。 1.析构函数是什么 析构函数是Python面向对象编程中的一个重要概念,它是在对象生命周期结束时自动调…

网工内推 | 浪潮原厂售前、方案经理,上市公司大平台,最高20K

01 浪潮集团 招聘岗位:售前经理 职责描述: 1、负责数字生态、数字教育、工业互联网、数字乡村、智慧城市、智慧交通等数字经济领域解决方案的售前工作,包括但不限于融合方案编制、项目调研、订制文档输出及客户咨询支持。 2、负责与公司各产…

数据完整性

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 数据完整性 数据完整性是关系数据库的一个重要特征,一般包含实体完整性、参照完整性和用户自定义完整性 3 种 实体完整性 实体完整性:规定表中的每…

VXLAN学习笔记

声明:该博客内容大部分参考参考链接整理 什么是VXLAN? VXLAN(Virtual Extensible LAN)即虚拟扩展局域网,是大二层网络中广泛使用的网络虚拟化技术。在源网络设备与目的网络设备之间建立一条逻辑VXLAN隧道,采用MAC in UDP的封装方…

Python的asyncio 多线程

-- 多线程、进程、协程是什么就不讲了,(就是你理解的一边呼吸,一边看文章) 仅解决问题的话,下边两篇不用看, Python 中的 async await 概念-CSDN博客 再深一点的看这个 Python中的多线程、进程、协程、…

Vue.js+SpringBoot开发个人健康管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 健康档案模块2.2 体检档案模块2.3 健康咨询模块 三、系统展示四、核心代码4.1 查询健康档案4.2 新增健康档案4.3 查询体检档案4.4 新增体检档案4.5 新增健康咨询 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpri…

【项目设计】基于Httplib和Mysql的视频播放

项目源码(绝对可以直接运行) 一、项目介绍 1. 对视频播放系统的认识 搭建视频共享播放服务器,可以让所有人通过浏览器访问服务器,实现视频的上传查看,以及管理并播放的功能。主要是完成服务器端的程序业务功能的实现…

腾讯云轻量4核8G12M服务器性能如何?价格感人

腾讯云轻量4核8G12M服务器配置446元一年,646元12个月,腾讯云轻量应用服务器具有100%CPU性能,系统盘为180GB SSD盘,12M带宽下载速度1536KB/秒,月流量2000GB,折合每天66.6GB流量,超出月流量包的流…

springboot276基于JS的个人云盘管理系统的设计与实现

个人云盘管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装个人云盘管理系统软件来发挥其…

开发反应式API

开发反应式API 开发反应式API1 使用SpringWebFlux1.1 Spring WebFlux 简介1.2 编写反应式控制器 2 定义函数式请求处理器3 测试反应式控制器3.1 测试 GET 请求3.2 测试 POST 请求3.3 使用实时服务器进行测试 4 反应式消费RESTAPI4.1 获取资源4.2 发送资源4.3 删除资源4.4 处理错…

大话设计模式——7.抽象工厂模式(Abstract Factory Pattern)

1.介绍 抽象工厂模式是工厂模式的进一步优化,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。属于创建型模式。 UML图: 2.示例 车辆制造工厂,不仅可以制造轿车也可以用来生产自行车。 1)Abs…

【技术类-02】python实现docx段落文字的“手动换行符(软回车)”变成“段落标记(硬回车)”

作品展示 背景需求: 制作周计划时,需要将周计划docx内所有的表格里的手动换行符(软回车)”变成“段落标记(硬回车)”, 全部改成段落标记(硬回车) 但是19份docx每份都要打…

人工智能入门学习笔记1:什么是人工智能

一、什么是人工智能 人工智能(Artificial Intelligence),是一个以计算机科学(Computer Science)为基础,由计算机、心理学、哲学等多学科交叉融合的交叉学科、新兴学科,研究、开发用于模拟、延伸和扩展人的智能的理论、…