Redis从入门到精通之底层数据结构快表QuickList详解

news2024/12/30 2:28:07

文章目录

  • 0.前言
  • 1. 快表的结构
    • 2. Redis 6.0 快表quicklist 基本结构
      • 2.1 成员变量
      • 2.1 主要操作
      • 2.1 推导结果
    • 3. 快表的操作
  • 3. 快表的优缺点
    • 3.1 优点:
    • 3.2 缺点:
  • 5. Redis从入门到精通系列文章

redis高阶篇.jpg

0.前言

上个篇章回顾,我们上个章节,讲了redis的底层数据结构简单动态字符串(SDS)详解和压缩列表(ZipList)详解。了解到SDS是Redis字符串数据类型的底层数据结构,它具有可变长度、二进制安全、缓冲区预分配等特点。ZipList压缩列表是用来表示列表和哈希表的数据结构,它是一种紧凑的、压缩的数据结构,可以存储多个元素,并且支持在表头和表尾进行快速的插入和删除操作,可以有效地减少内存占用。

那么本章讲解Redis中的快表(QuickList),它是一种特殊的数据结构,用于存储一系列的连续节点,每个节点可以是一个整数或一个字节数组。快表是Redis中的底层数据结构之一,常用于存储有序集合(Sorted Set)等数据类型的底层实现。在本文中,我们将深入了解Redis中的快表,包括快表的结构和操作等。

1. 快表的结构

Redis中的快表(QuickList)是由多个节点(Node)组成的双向链表,每个节点都是一个ziplist(压缩列表)。快表中的每个节点包含了多个元素,每个元素可以是一个整数或一个字节数组。快表的结构如下图所示:

+---------+---------+---------+-------+
|  ziplist|  ziplist|  ziplist|  ...  |
+---------+---------+---------+-------+
|  prev   |  next   |  len    |  len  |
+---------+---------+---------+-------+
|  ...    |  ...    |  ...    |  ...  |
+---------+---------+---------+-------+

其中,ziplist是压缩列表,prev和next是指向前一个节点和后一个节点的指针,len是当前节点中元素的个数。
image.png

两端各有2个橙黄色的节点,是没有被压缩的。它们的数据指针zl指向真正的ziplist。中间的其它节点是被压缩过的,它们的数据指针zl指向被压缩后的ziplist结构,即一个quicklistLZF结构。
左侧头节点上的ziplist里有2项数据,右侧尾节点上的ziplist里有1项数据,中间其它节点上的ziplist里都有3项数据(包括压缩的节点内部)。这表示在表的两端执行过多次push和pop操作后的一个状态。
现在我们来大概计算一下quicklistNode结构中的count字段这16bit是否够用。
Redis 6.0 版本中的快表(QuickList)与 Redis 4.0 版本中的快表基本结构相同,都是由多个 quicklistNode 节点组成,其中每个节点都包含一个 ziplist 和一些元数据信息。快表中的元素按照从表头到表尾的顺序依次存储。

2. Redis 6.0 快表quicklist 基本结构

typedef struct quicklist {
    quicklistNode *head;
    quicklistNode *tail;
    unsigned long count;
    unsigned int len; // quicklist 节点数
    int fill : 16; // 压缩列表节点所能容纳的最大元素个数
    unsigned int compress : 16; // 压缩比例,0 表示不压缩,1 表示每两个节点压缩一个节点
    unsigned int bookmark_count; // 快照节点数量
    quicklistBookmark *bookmarks; // 快照节点数组
} quicklist;

在这里插入图片描述

2.1 成员变量

  • head 和 tail:分别指向快表的头部和尾部 quicklistNode 节点。

  • count:快表中元素的数量。

  • len:快表中 quicklistNode 节点的数量。

  • fill:ziplist 节点所能容纳的最大元素个数。

  • compress:压缩比例,0 表示不压缩,1 表示每两个节点压缩一个节点。

  • bookmark_count 和 bookmarks:快照节点数量和快照节点数组,用于支持快照功能。

2.1 主要操作

  • 在表头或表尾插入元素:根据情况选择头部或尾部的 ziplist,并在 ziplist 的头部或尾部插入元素。

  • 在表头或表尾删除元素:根据情况选择头部或尾部的 ziplist,并在 ziplist 的头部或尾部删除元素。

  • 按索引获取元素:首先根据索引定位到对应的 quicklistNode,然后在 quicklistNode 的 ziplist 中按照索引获取元素。

  • 范围查询元素:首先根据起始索引定位到对应的 quicklistNode,然后在 quicklistNode 的 ziplist 中按照范围查询元素。

  • 插入或删除元素时,如果某个 quicklistNode 的元素个数超过了指定的阈值,可以选择将该 quicklistNode 压缩为一个新的 quicklistNode,以减少内存占用。

  • 支持快照功能,可以在快表中的任意位置插入一个快照节点,用于快速恢复数据。

2.1 推导结果

我们已经知道,ziplist大小受到list-max-ziplist-size参数的限制。按照正值和负值有两种情况:

当这个参数取正值的时候,就是恰好表示一个quicklistNode结构中zl所指向的ziplist所包含的数据项的最大值。list-max-ziplist-size参数是由quicklist结构的fill字段来存储的,而fill字段是16bit,所以它所能表达的值能够用16bit来表示。
当这个参数取负值的时候,能够表示的ziplist最大长度是64 Kb。而ziplist中每一个数据项,最少需要2个字节来表示:1个字节的prevrawlen,1个字节的data(len字段和data合二为一;详见上一篇)。所以,ziplist中数据项的个数不会超过32 K,用16bit来表达足够了。

实际上,在目前的quicklist的实现中,ziplist的大小还会受到另外的限制,根本不会达到这里所分析的最大值。
在快表中,每个节点的大小是固定的。因此,当节点中的元素数量增加时,需要动态地添加新的节点来存储数据,这样可以保持快表的高效性。

3. 快表的操作

Redis中的快表支持以下常用的操作:

  • 快表的创建
quicklist *ql = quicklistNew();
  • 快表的添加
quicklistPushTail(ql, s, len);

其中,s是一个字节数组,len是字节数组的长度,表示在快表的尾部添加一个字节数组元素。

quicklistPushTail(ql, &value, sizeof(value));

其中,value是一个整数,表示在快表的尾部添加一个整数元素。

  • 快表的删除
quicklistDelIndex(ql, node, index);

其中,node是指向要删除的节点的指针,index是节点中要删除元素的下标。

  • 快表的遍历
for (quicklistNode *node = ql->head; node; node = node->next) {
    unsigned char *data = NULL;
    unsigned int sz;
    long long val;
    int ret = quicklistGet(node, &data, &sz, &val);
    if (ret == -1) {
        printf("data: %s, size: %d\n", data, sz);
    } else {
        printf("value: %lld\n", val);
    }
}

其中,node是指向当前节点的指针,data是节点中的字节数组元素,sz是字节数组元素的长度,val是节点中的整数元素。

  • 快表的长度
unsigned long quicklistCount(const quicklist *ql);

以上是常用的快表操作,还有其他的操作可以参考Redis源代码中的quicklist.h和quicklist.c文件。

3. 快表的优缺点

3.1 优点:

  • 快表的节点大小固定,可以有效地避免内存碎片的发生。
  • 快表支持动态增加和删除节点,可以随着数据的增长而自动扩容或缩容,不需要预先分配空间。
  • 快表的节点采用ziplist的紧凑存储方式,使得节点访问和遍历的效率较高。同时,快表支持从头和尾部两个方向同时遍历节点。

3.2 缺点:

  • 快表的节点大小固定,如果节点中的元素数量较少,会造成一定的空间浪费。
  • 快表中的元素只能是整数或字节数组,不支持其他数据类型的存储。
  • 快表的插入和删除操作的效率较低,因为在插入或删除元素时,需要移动后面的元素,可能会导致大量的内存复制操作。如果需要频繁进行插入和删除操作,建议使用其他数据结构,例如链表。
  • 当快表中的元素数量较大时,遍历整个快表的效率也可能较低,因为快表是由多个节点组成的链表,需要依次遍历每个节点才能访问所有元素。
    #4. 总结
    快表适合存储一些数量较少但有序的元素,例如有序集合(Sorted Set)中的成员和分值。在实际应用中,需要根据具体的业务场景选择合适的底层数据结构。

5. Redis从入门到精通系列文章

《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》

在这里插入图片描述

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

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

相关文章

计算机中丢失msvcp140.dll的解决方案-由于找不到msvcp140.dll的解决方法

本教程操作系统:电脑 Windows系统、 msvcp140.dll是电脑文件中的dll文件(动态链接库文件)。如果计算机中丢失了某个dll文件,可能会导致某些软件和游戏等程序无法正常启动运行,并且导致电脑系统弹窗报错。 在我们打开…

STM32串口DMA双缓冲,数据接收与发送,HAL库实现

STM32串口DMA双缓冲 1.简介 STM32F429系列DMA支持双缓冲模式进行数据传输,相当于数字电路设计领域的乒乓操作,但是HAL库并没有实现像单缓冲区一样可以简单使用的函数,有的方法是使用单缓冲的方式,但是通过接收半满的中断控制CPU…

头文件header file和源文件 source file

头文件 header file,后缀是.h,头文件负责类的定义,函数声明,常量的定义 源文件source file,后缀是.cpp, 函数的实现 最主要的作用就是将函数的声明和实现分开,如果想将类和函数交给别人使用&a…

python基本语法知识(五)——面向对象

类和对象 例子1 class Student:name Nonegender Nonenationality Nonenative_place None # 籍贯age None# 类内的成员方法,第一个参数必须为 self,# self相当于是当前对象def say_hi(self):print(f"大家好,我是{self.name}")def say_hi2(self, msg):print(f&q…

自学网络安全怎么规划路线?

01 什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面…

HuggingFace Bert语言模型抽取句子表征向量

1. 安装相应的包 pip install transformers2. 具体代码 from transformers import BertTokenizer, BertModeltokenizer BertTokenizer.from_pretrained(bert_base_cased, cache_dir"dblp/bert_base_cased", local_files_onlyTrue) model BertModel.from_pretrain…

第七十一天学习记录:对陈正冲编著《C 语言深度解剖》中关于1、2、4,5章作者留下部分问题的学习

问&#xff1a;有如下代码。 static int j;void fun1(void) {static int i 0;i; }void fun2(void) {j 0; j; }int main() {int k 0;for (k 0; k<10; k){fun1();fun2();}return 0; }i 和 j 的值分别是什么,为什么&#xff1f; 答&#xff1a; 在这份代码中&#xff0c;变…

Dtop环球嘉年华推动Web 3.0国际电商领域的革新

随着互联网技术的与日俱进和数字经济的高速发展,国际贸易正在经历一场重大变革。其中,跨境电商作为一种新兴的商业模式,正在全球迅速崛起。然而,自2021年以来,跨境电商行业也面临着各种风险和挑战,如各国增值税新规、电商账号封禁事件以及海运价格持续上涨等冲击。这些因素共同…

Spark SQL数据帧与数据集

文章目录 一、数据帧 - DataFrame&#xff08;一&#xff09;DataFrame概述&#xff08;二&#xff09;将RDD转成DataFrame 二、数据集 - Dataset&#xff08;一&#xff09;Dataset概述&#xff08;二&#xff09;将RDD转成DataSet&#xff08;三&#xff09;DataFrame与Datas…

ATA-4000系列高压功率放大器——超声导波中的典型应用

ATA-4000系列高压功率放大器——超声导波中的典型应用 超声导波技术 超声导波(guided waves ultrasonic)技术是一项近年来广受关注的无损检测技术。导波是由于介质边界存在而被限制在介质中传播的、同时其传播方向平行于介质边界的波。超声导波较早期的研究由一些著名学者完成&…

react + antd实现动态切换主题功能(适用于antd5.x版本)

前言 在之前的几篇文章中&#xff08;React Antd实现动态切换主题功能之二&#xff08;默认主题与暗黑色主题切换&#xff09;、React Antd实现动态切换主题功能&#xff09;介绍了antd实现动态切换主题功能&#xff0c;文章里介绍的方法在antd5.x版本却不适用&#xff0c;因…

【UE5】分分钟简单使用像素流云服务(Pixel Streaming)

【UE5】分分钟简单使用像素流云服务&#xff08;Pixel Streaming&#xff09; 前言 UE5的Pixel Streaming已经封装的很好&#xff0c;简单三步实现简单的服务搭建。 安装插件打包项目运行服务 注&#xff1a;实例平台为Windows 安装插件 编辑→插件→输入查询Pixel Strea…

Java之~Bigdicmal的长度,小数点后用0补位

/*** 获取bigdicmal的长度* param number 需要截取的数字* param num 需要保留小数点后的位数* return*/ public static int checkBigDecimalLength(String number ,int num){String s getSupString(number,num);return s.length(); }/*** 补充后面数值0* param number 需要截…

5G技术学习——5GNR帧结构和空口资源

这里写目录标题 4G时域定义&#xff1a;资源划分 5GNR中时域 频域 与空域资源 循环前缀CP:背景和原理5G帧结构&#xff1a;基本框架5G slot分类 5G 频域资源5G频域资源基本概念信道带宽与传输带宽BWP定义及其应用场景 4G 时域定义&#xff1a; 帧&#xff1a;10ms&#xff0c;…

【go-zero】go-zero微服务实战系列九 聚合策略 极致优化秒杀性能(转)

上一篇文章中引入了消息队列对秒杀流量做削峰的处理,我们使用的是Kafka,看起来似乎工作的不错,但其实还是有很多隐患存在,如果这些隐患不优化处理掉,那么秒杀抢购活动开始后可能会出现消息堆积、消费延迟、数据不一致、甚至服务崩溃等问题,那么后果可想而知。本篇文章我们…

深度学习-pytorch_lightning框架使用实例

下面是我写过的一个pytorch_lightning项目的代码框架。关键代码已经省略。 模型构建 import pytorch_lightning as pl from pytorch_lightning.plugins.io import TorchCheckpointIO as tcio import torch from torch import nn import torch.nn.functional as F from torch.…

师生相逢,潇潇洒洒出品

师生相逢2023年6月10日潇潇洒洒出品骑行肩并肩 相望曾相识①遥忆多年前 青春勃发时豪情梦摘星 清纯玉壶冰感叹岁月老 友情弥久新寄情山水间 天涯不负卿①骑行路上&#xff0c;偶遇30年前的学生&#xff0c;现在是骑行群的骑友&#xff0c;共同的兴趣爱好使我们30年后再相逢&…

【服务器数据恢复】热备盘激活失败导致raid5瘫痪的数据恢复案例

服务器数据恢复环境&#xff1a; 一台EMC存储中数块磁盘组建了一组raid5磁盘阵列&#xff0c;阵列中有2块热备盘&#xff1b;上层采用ZFS文件系统&#xff0c;划分了一个lun&#xff0c;供sun小机使用。 服务器故障&检测&#xff1a; 存储在正常运行中突然崩溃无法使用&…

STM32单片机(五)第一节:EXTI外部中断

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

AST反混淆js代码——猿人学竞赛第二题

猿人学JS比赛第二题解混淆 分析代码解混淆代码结果 前一段时间参加猿人学js比赛&#xff0c;今天把第二题的还原做一下笔记。 分析代码 首先&#xff0c;我们需要对混淆js代码进行分析&#xff0c;确定还原的思路&#xff0c;才能书写解混淆代码进行还原。代码是静态的&#x…