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

文章目录

  • 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详解和使用示例》

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Win10 系统专业版远程桌面如何才能多用户同时登录使用?

环境: Win10专业版19041 RDPWrap-v1.6.2 dell5493笔记本 问题描述: Win10 系统专业版远程桌面如何才能多用户同时登录使用? 解决方案: 安装RDPWrap 1.关闭remote desktop services服务 安装RDP之前,要先关闭re…

Kuberentes,k8s诞生简介

一、前言 什么是k8s? Kuberentes 是基于容器的集群管理平台,它的简称,是K8S。有人说之所以叫k8s,是因为k到s中间有8个字母,因此叫k8s,也有人说,在使用k8s的安装配置流程中,共分为8…

验证attention是否在图像分类问题上起决定性作用

来源:投稿 作者:摩卡 编辑:学姐 Motivation 现阶段出现了大量的Transformer-style图像分类模型,并且这些模型在ImageNet上取得了不俗的成绩,这些Transformer-style模型将取得高性能的功劳归功于Multi-head attention注…

12.异常检测

12.1 异常检测的应用 异常检测最常见的应用是欺诈检测; 如果你有很多用户,每个用户都在从事不同的的活动,你可以对不同的用户活动计算特征变量,然后可以建立一个模型来表示用户表现出各种行为的可能性,用来表示用户行…

微服务 springcloud 05 hystrix框架,降级,可视化Hystrix dashboard 仪表盘,熔断

01.微服务宕机时,ribbon 无法转发请求 关闭 user-service 和 order-service 02.hystrix框架 03.创建hystrix项目,hystrix与ribbon经常一起出现 第一步:复制 sp06-ribbon 项目,命名为sp07-hystrix 选择 sp06-ribbon 项目&#…

高并发架构设计方法

我们知道,“高并发”是现在系统架构设计的核心关键词。一个架构师如果设计、开发的系统不支持高并发,那简直不好意思跟同行讨论。但事实上,在架构设计领域,高并发的历史非常短暂,这一架构特性是随着互联网,…

【JVM】日志分析工具--gcviewer的使用

文章目录 gcviewer是什么?gcviewer的使用最后 gcviewer是什么? GCViewer是一个小工具,可以可视化Sun / Oracle、IBM、HP和BEA Java虚拟机生成的详细GC输出。它是在GNU LGPL下发布的自由软件。—官网翻译 gcviewer的使用 文章使用的配置 工具…

权限验证框架之Shiro

文章目录 前言shiro 核心项目构建默认Session模式配置测试接口Realm编写权限测试无权限测试登录测试权限测试 前后端分离tokenJWTFilter重写认证修改配置 总结 前言 交替换个脑子,一直搞考研的东西,实在是无聊。所以顺便把工程上的东西,拿来…

探索Redis内部数据结构

Redis支持多种数据结构,每种数据结构都有其特定的用途。下面对Redis支持的主要数据结构进行详细阐述: 一、字符串(String) 字符串是Redis最基本的数据结构,可以存储一个字符串或者二进制数据,例如图片、序…

HID协议学习

HID协议学习 0. 文档资料 USB_HID协议中文版_USB接口HID设备_AUJsRmB9kg.pdf HID报告描述符精细说明_mgCxM8_ci9.pdf hut1_22_U3cvnwn_ZZ.pdf 1. 基本概念 HID协议是一种基于USB的通讯协议,用于在计算机和输入设备之间进行数据传输。HID协议定义了标准的数据格…

如何实现在线书签内容替换

书签广泛应用于企业的各种办公自动化业务场景中。例如:在范式合同模板中将甲乙方书签自动替换成具体的公司名称;在红头文件模板中将红头标题书签替换成具体的行政指令;在各种协议模板中将协议日期书签替换为当前日期;等等。 在这…

【Elacticsearch】 原理/数据结构/面试经典问题整理

对Elacticsearch 原理/数据结构/面试经典问题整理的文章; 映射 | Elasticsearch: 权威指南 | Elastic Elacticsearch介绍 Elasticsearch,这里简称ES。ES是一个开源的高可用高扩展的分布式全文搜索与分析引擎,可以提供PB级近实时的数据存储和检索能力&am…

《离散数学》:集合、关系和函数

〇、前言 这章将会对集合、以及集合之上的关系、以及两个集合之间的映射情况做一个细致的讨论。集合作为数学和其他领域中的基础概念,具有广泛的应用和重要的地位。它为数学建立了基本的体系和推理方法,为各个领域的研究和应用提供了一种统一的描述和分…

基于web漏洞扫描及分析系统设计_kaic

基于web漏洞扫描及分析系统设计 摘 要 随着信息技术的发展和网络应用在我国的普及,针对我国境内信息系统的恶意网络攻击也越来越多,并且随着黑客攻击技术的不断地更新,网络犯罪行为变得越来越难以应对,用户日常访问的网站是否安全…

Mysql主从复制及读写分离

🍓 简介:java系列技术分享(👉持续更新中…🔥) 🍓 初衷:一起学习、一起进步、坚持不懈 🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏 🍓 希望这篇文章对你有所帮助,欢…

LaTeX插入参考文献

接着上一篇,用EndNote组织参考文献,然后再导入到LeTex中感觉不太好用,然后就学习了一下BibTeX来管理参考文献,发现还可以,这里记录一下,方便以后查阅。 LaTeX插入参考文献 thebibliographyBibTeX参考资料 t…

前端 sentry 接入钉钉机器人

sentry 接入钉钉机器人 打开钉钉,添加机器人 此时会得到Webhook地址,记录一下,以后会用到 sentry 端设置 看看这里有木有钉钉插件,有的话开启插件,并配置这里我说一下没有的情况下,我们何如设置 这里需要填写webhook url 这个的url 需要是一个公网的地址,不可以是本地…

使用Unity开发一个独立的区块链

Arouse Blockchain [Unity独立区块链] ❗️千万别被误导,上图内容虽然都在项目中可寻,但与目前区块链的业务代码关联不大,仅供宣传作用(总得放些图看着好看)。之所以有以上内容是项目有个目标功能是希望每个用户在区块链上都有一个独一无二的…

View UI Plus (iview)表格单选实现教程

View UI Plus 是 View Design 设计体系中基于 Vue.js 3 的一套 UI 组件库,主要用于企业级中后台系统 View UI,即原先的 iView,从 2019 年 10 月起正式更名为 View UI,并使用全新的 Logo View UI Plus 实现表格单选,这…

首次使用云服务器搭建网站(二)

书接上文,我们已经完成了服务器的租赁,宝塔面板的下载与安装。 接下来我们将正式开始网站搭建。 一、网站创建 点击网站、添加站点 输入网站域名、数据库选择MySQL数据库,选择utf8,数据库账号密码会自动生成。无论你要创建什么样…