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

REDIS19_zipList压缩列表详解、快递列表 - QuickList、跳表 - SkipList

文章目录

  • ①. 压缩列表 - zipList
  • ②. 快递列表 - QuickList
  • ③. 跳表 - SkipList

①. 压缩列表 - zipList

  • ①. ZipList是一种特殊的"双端链表",由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作,并且该操作的时间复杂度为O(1) (oxff:11111111)

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

typedef struct zlentry {unsigned int prevrawlensize; /* 上一个链表节点占用的长度*/unsigned int prevrawlen;     /* 存储上一个链表节点的长度数值所需要的字节数 */unsigned int lensize;        /* 存储当前链表节点长度数值所需要的字节数*/unsigned int len;            /* 当前链表节点所占用长度 */unsigned int headersize;     /* 当前链表节点的头部大小:prevrawlensize + lensize. */unsigned char encoding;      /* 编码方式*/unsigned char *p;            /* 压缩链表以字符串的形式保存,该指针指向当前节点起始位置 */
} zlentry;
  • ②. ZipList中的Entry并不像普通链表那样记录前后节点的指针,因为记录两个指针要占用16个字节,浪费内存。而是采用了下面的结构
  1. previous_entry_length:前一节点的长度,占1个或5个字节
    如果前一节点的长度小于254字节,则采用1个字节来保存这个长度值
    如果前一节点的长度大于254字节,则采用5个字节来保存这个长度值,第一个字节为0xfe,后四个字节才是真实长度数据
  2. encoding:编码属性,记录content的数据类型(字符串还是整数)以及长度,占用1个、2个或5个字节
  3. contents:负责保存节点的数据,可以是字符串或整数
    在这里插入图片描述
  • ③. ZipListEntry中的encoding编码分为字符串和整数两种:如下所示④⑤所示

  • ④. 字符串:如果encoding是以"00"、"01"或者"10"开头,则证明content是字符串
    例如,我们要保存字符串:"ab"和 “bc”
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • ⑤. 整数:如果encoding是以"11"开始,则证明content是整数,且encoding固定只占用1个字节
    例如,一个ZipList中包含两个整数值:“2"和"5”
    在这里插入图片描述在这里插入图片描述

  • ⑥. ZipList的连锁更新问题

  1. ZipList的每个Entry都包含previous_entry_length来记录上一个节点的大小,长度是1个或5个字节:
    如果前一节点的长度小于254字节,则采用1个字节来保存这个长度值
    如果前一节点的长度大于等于254字节,则采用5个字节来保存这个长度值,第一个字节为0xfe,后四个字节才是真实长度数据
  2. 现在,假设我们有N个连续的、长度为250~253字节之间的entry,因此entry的previous_entry_length属性用1个字节即可表示,如图所示: 这个时候在头节点插入一个254byte的entry

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

  • ⑦. ZipList特性:
  1. 压缩列表的可以看做一种连续内存空间的"双向链表"
  2. 列表的节点之间不是通过指针连接,而是记录上一节点和本节点长度来寻址,内存占用较低
  3. 如果列表数据过多,导致链表过长,可能影响查询性能
  4. 增或删较大数据时有可能发生连续更新问题
    在这里插入图片描述
  • ⑧. 明明有链表了,为什么出来一个压缩链表?
  1. 普通的双向链表会有两个指针,在存储数据很小的情况下,我们存储的实际数据的大小可能还没有指针占用的内存大,得不偿失。ziplist是一个特殊的双向链表没有维护双向指针: prev next;而是存储上一个entry的长度和当前entry的长度,通过长度推算下一个元素在什么地方
  2. 链表在内存中一般是不连续的,遍历相对比较慢,而ziplist可以很好的解决这个问题
  3. 头节点里有头节点里同时还有一个参数len,和string类型提到的SDS 类似,这里是用来记录链表长度的。因此获取链表长度时不用再遍历整个链表,直接拿到len值就可以了,这个时间复杂度是 O(1)

②. 快递列表 - QuickList

  • ①. 问题1:ZipList虽然节省内存,但申请内存必须是连续空间,如果内存占用较多,申请内存效率很低。怎么办?
    为了缓解这个问题,我们必须限制ZipList的长度和entry大小。

  • ②. 问题2:但是我们要存储大量数据,超出了ZipList最佳的上限该怎么办?
    我们可以创建多个ZipList来分片存储数据

  • ③. 数据拆分后比较分散,不方便管理和查找,这多个ZipList如何建立联系?
    Redis在3.2版本引入了新的数据结构QuickList,它是一个双端链表,只不过链表中的每个节点都是一个ZipList
    在这里插入图片描述

  • ④. 为了避免QuickList中的每个ZipList中entry过多,Redis提供了一个配置项:list-max-ziplist-size来限制

  1. 如果值为正,则代表ZipList的允许的entry个数的最大值
  2. 如果值为负,则代表ZipList的最大内存大小,分5种情况:(其默认值为 -2)
    -1:每个ZipList的内存占用不能超过4kb
    -2:每个ZipList的内存占用不能超过8kb
    -3:每个ZipList的内存占用不能超过16kb
    -4:每个ZipList的内存占用不能超过32kb
    -5:每个ZipList的内存占用不能超过64kb
    在这里插入图片描述
  • ⑤. ziplist压缩配置:list-compress-depth 0:表示一个quicklist两端不被压缩的节点个数。这里的节点是指quicklist双向链表的节点,而不是指ziplist里面的数据项个数,参数list-compress-depth的取值含义如下:
  1. 0: 是个特殊值,表示都不压缩。这是Redis的默认值
  2. 1: 表示quicklist两端各有1个节点不压缩,中间的节点压缩
  3. 2: 表示quicklist两端各有2个节点不压缩,中间的节点压缩
  4. 3: 表示quicklist两端各有3个节点不压缩,中间的节点压缩
    依此类推…
  • ⑥. 以下是QuickList的和QuickListNode的结构源码:
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • ⑦. 我们接下来用一段流程图来描述当前的这个结构
    在这里插入图片描述

  • ⑧. QuickList的特点:

  1. 是一个节点为ZipList的双端链表
  2. 节点采用ZipList,解决了传统链表的内存占用问题
  3. 控制了ZipList大小,解决连续内存空间申请效率问题
  4. 中间节点可以压缩,进一步节省了内存

③. 跳表 - SkipList

  • ①. SkipList(跳表)首先是链表,但与传统链表相比有几点差异:
  1. 元素按照升序排列存储
  2. 节点可能包含多个指针,指针跨度不同
    在这里插入图片描述
    在这里插入图片描述
  • ②. 源码分析
    在这里插入图片描述
  • ③. SkipList的特点:
  1. 跳跃表是一个双向链表,每个节点都包含score(分数)和ele(内容)值
  2. 节点按照score值排序,score值一样则按照ele字典排序
  3. 每个节点都可以包含多层指针,层数是1到32之间的随机数
  4. 不同层指针到下一个节点的跨度不同,层级越高,跨度越大
  5. 增删改查效率与红黑树基本一致,实现却更简单

相关文章:

REDIS19_zipList压缩列表详解、快递列表 - QuickList、跳表 - SkipList

文章目录①. 压缩列表 - zipList②. 快递列表 - QuickList③. 跳表 - SkipList①. 压缩列表 - zipList ①. ZipList是一种特殊的"双端链表",由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作,并且该操作的时间复杂度为O(1) (oxff:11111111) type…...

JavaScript 基础 - 第3天

文章目录JavaScript 基础 - 第3天笔记数组数组的基本使用定义数组和数组单元数据单元值类型数组长度属性操作数组JavaScript 基础 - 第3天笔记 数组 数组的基本使用 定义数组和数组单元 <script>// 1. 语法&#xff0c;使用 [] 来定义一个空数组// 定义一个空数组let…...

23.3.26总结

康托展开 是一个全排列与自然数的映射关系&#xff0c;康托展开的实质是计算当前序列在所有从小到大的全排列中的顺序&#xff0c;跟其逆序数有关。 例如&#xff1a;对于 1,2,3,4,5 来说&#xff0c;它的康托展开值为 0*4&#xff01;0*3&#xff01;0*2&#xff01;0*1&…...

【Java学习笔记】37.Java 网络编程

Java 网络编程 网络编程是指编写运行在多个设备&#xff08;计算机&#xff09;的程序&#xff0c;这些设备都通过网络连接起来。 java.net 包中 J2SE 的 API 包含有类和接口&#xff0c;它们提供低层次的通信细节。你可以直接使用这些类和接口&#xff0c;来专注于解决问题&…...

Azure OpenAI 官方指南03|DALL-E 的图像生成功能与安全过滤机制

2021年1月&#xff0c;OpenAI 推出 DALL-E。这是 GPT 模型在图像生成方面的人工智能应用。其名称来源于著名画家、艺术家萨尔瓦多 • 达利&#xff08;Dal&#xff09;和机器人总动员&#xff08;Wall-E&#xff09;。DALL-E 图像生成器&#xff0c;能够直接根据文本描述生成多…...

【数据结构】堆

文章目录前言堆的概念及结构堆初始化堆的判空堆的销毁插入数据删除数据堆的数据个数获取堆顶数据用数组创建堆对数组堆排序有关topk问题整体代码展示写在最后前言 &#x1f6a9;前面了解了树&#xff08;-> 传送门 <-&#xff09;的概念后&#xff0c;本章带大家来实现一…...

电脑硬盘文件数据误删除/格式化为什么可以恢复? 怎么恢复?谈谈文件删除与恢复背后的原理

Hello 大家好&#xff0c; 我是元存储~ 主页&#xff1a;元存储的博客_CSDN博客 1. 硬盘数据丢失场景 我们在每天办公还是记录数据的时候&#xff0c;文件存储大多数都是通过硬盘进行存储的&#xff0c;因此&#xff0c;使用多了&#xff0c;各种问题就会出现&#xff0c;比如…...

Gateway服务网关

Spring Cloud Gateway为微服务架构提供一种简单有效的统一的 API 路由管理方式。Gateway网关是所有微服务的统一入口。网关的核心功能特性&#xff1a;请求路由和负载均衡&#xff1a;一切请求都必须先经过gateway&#xff0c;但网关不处理业务&#xff0c;而是根据某种规则&am…...

K8S + GitLab + Jenkins自动化发布项目实践(一)

K8S GitLab Jenkins自动化发布项目实践&#xff08;一&#xff09;发布流程设计安装Docker服务部署Harbor作为镜像仓库部署GitLab作为代码仓库常用Git命令发布流程设计 #mermaid-svg-pe9VmFytb9GmqMvG {font-family:"trebuchet ms",verdana,arial,sans-serif;font-…...

【数据结构篇C++实现】- 堆

文章目录&#x1f680;一、堆的原理精讲⛳&#xff08;一&#xff09;堆的概念⛳&#xff08;二&#xff09;看图识最大堆⛳&#xff08;三&#xff09;详解堆是用数组表示的树&#x1f680;二、堆的向下调整算法&#x1f680;三、堆的向上调整算法&#x1f680;四、将任意一棵…...

C++笔试题

作用域运算符(::)的作用&#xff1a;1.存在具有相同名称的局部变量时&#xff0c;访问全局变量。2.在类之外定义类相关函数。3.访问类的静态变量。4.在多重继承的情况下&#xff0c;如果两个基类中存在相同的变量名&#xff0c;可以使用作用域运算符来进行区分。5.限定成员函数…...

【Python】基本语法

数据类型 通过 print(type(x)) 可以输出 x 的数据类型&#xff0c;type() 函数可以获取数据类型 整数 a 10 print(type(a)) 浮点数 a 0.5 print(type(a)) 字符串 a hello print(type(a)) 获取字符串长度 a hello print(len(a))字符串拼接 a hello b world prin…...

用栈实现队列(图示超详解哦)

全文目录引言用栈实现队列题目介绍思路简述实现栈的部分队列的部分创建队列判断队列是否为空在队列尾入在队列头出访问队头元素释放队列总结引言 在上一篇文章中&#xff0c;我们了解了用两个队列实现栈。在这篇问章中将继续介绍用两个栈实现队列的OJ练习&#xff1a; 用栈实现…...

Spring - Spring 注解相关面试题总结

文章目录01. Spring 配置方式有几种&#xff1f;02. Spring 如何实现基于xml的配置方式&#xff1f;03. Spring 如何实现基于注解的配置&#xff1f;04. Spring 如何基于注解配置bean的作用范围&#xff1f;05. Spring Component, Controller, Repository, Service 注解有何区别…...

【数据结构】实现二叉树的基本操作

目录 1. 二叉树的基本操作 2. 具体实现 2.1 创建BinaryTree类以及简单创建一棵树 2.2 前序遍历 2.3 中序遍历 2.4 后序遍历 2.5 层序遍历 2.6 获取树中节点的个数 2.7 获取叶子节点的个数 2.8 获取第K层节点的个数 2.9 获取二叉树的高度 2.10 检测值为val的元素是否…...

代码随想录算法训练营第五十二天| ● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

300.最长递增子序列 看完题后的思路 dp[i] [0,i]子数组中,以nums[i]结尾的子序列的长度 dp[i]dp[j]1 j从i-1向0遍历,在所有nums[j]<nums[i]中dp[j]最大 初始化 dp[0]1 代码 class Solution {public int lengthOfLIS(int[] nums) {if (nums.length0){return 0;}int[] dpne…...

手机验证发送及其验证(基于springboot+redis)保姆级

在Java开发中&#xff0c;发送手机验证码时需要考虑以下几个问题&#xff1a; 验证码的有效期&#xff1a;验证码应该有一定的有效期&#xff0c;一般设置为几分钟或者十几分钟。过期的验证码应该被认为是无效的&#xff0c;不能用于验证用户身份。手机号码格式的校验&#xf…...

【JavaScript 逆向】数美滑块逆向分析

声明本文章中所有内容仅供学习交流&#xff0c;相关链接做了脱敏处理&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01;案例目标验证码&#xff1a;aHR0cHM6Ly93d3cuaXNodW1laS5jb20vbmV3L3Byb2R1Y3QvdHcvY29kZQ以上均做了脱敏处理&#xff0c;Base64 编码及解码方…...

多任务之线程

文章目录一、多任务是什么&#xff1f;二、多任务-线程四、通过继承Tread类完成创建线程五、资源竞争六、同步与互斥锁七、对峙与避免死锁一、多任务是什么&#xff1f; 多个函数同时执行一件事情就是多任务&#xff0c;没有多任务的时候任务执行都是按照顺序的&#xff0c;而…...

(数字图像处理MATLAB+Python)第二章数字图像处理基础-第二节:色度学基础与颜色模型

文章目录一&#xff1a;颜色匹配二&#xff1a;CIE 1931-RGB系统三&#xff1a;CIE 1931标准色度系统四&#xff1a;CIE 1976Lab均匀颜色空间五&#xff1a;孟塞尔表色系统&#xff08;1&#xff09;孟塞尔明度(Value&#xff0c;记为V)&#xff08;2&#xff09;孟塞尔彩度(Ch…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...