【Redis】基础数据结构-quicklist

news2024/10/6 6:49:36

Redis List

在Redis3.2版之前,Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis使用压缩列表实现,否则Redis使用双向链表实现。

ziplist存在问题

  1. 不能保存过多的元素,否则查找复杂度高,性能降低。

  2. 由于每个节点保存了前一个节点的长度,不同长度使用的字节数不一样,所以在更新节点的时候有可能引起长度的变化导致连锁更新问题。

为了解决上面两个问题,在Redis3.2版之后,引入了quicklist。

quicklist

quicklist可以理解为是ziplist和链表的结合体,一个quicklist是一个双向链表,链表中的每一个节点是一个ziplist。

quicklist结构定义
typedef struct quicklist {
    // 头指针
    quicklistNode *head;
    // 尾指针
    quicklistNode *tail;
    unsigned long count;        /* 列表中的元素总个数,也就是所有ziplist中包含的元素数量之和 */
    unsigned long len;          /* 链表中节点的个数 */
    int fill : QL_FILL_BITS;              /* 表示ziplist的大小 */
    unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
    unsigned int bookmark_count: QL_BM_BITS;
    quicklistBookmark bookmarks[];
} quicklist;
  • head:指向头结点的指针

  • tail:指向尾节点的指针

  • count:列表中的元素总个数,等于所有节点的ziplist中包含的元素数量之和

  • len:quicklist中quicklistNode节点的个数

  • fill:用来限制quicklistNode中ziplist的大小,为正数时代表ziplist中最多能包含的元素个数,为负数时有以下几种情况:

    数值含义
    -1表示ziplist的字节数不能超过4KB
    -2表示ziplist的字节数不能超过8KB
    -3表示ziplist的字节数不能超过16KB
    -4表示ziplist的字节数不能超过32KB
    -5表示ziplist的字节数不能超过64KB

​除此之外,也可以通过list-max-ziplist-size参数配置最大的字节数。

quicklistNode结构定义
typedef struct quicklistNode {
    // 前一个节点
    struct quicklistNode *prev;
    // 下一个节点
    struct quicklistNode *next;
    // 指向ziplist压缩列表的指针
    unsigned char *zl;
    unsigned int sz;             /* ziplist压缩列表的字节数 */
    unsigned int count : 16;     /* ziplist压缩列表的元素个数 */
    unsigned int encoding : 2;   /* 编码格式:RAW==1 or LZF==2 */
    unsigned int container : 2;  /* NONE==1 or ZIPLIST==2 */
    unsigned int recompress : 1; /* 是否被压缩 */
    unsigned int attempted_compress : 1; /* 是否可以被压缩 */
    unsigned int extra : 10; /* 预留bit位*/
} quicklistNode;
quicklist创建
quicklist *quicklistCreate(void) {
    struct quicklist *quicklist;
    // 分配空间
    quicklist = zmalloc(sizeof(*quicklist));
    // 初始化头尾节点
    quicklist->head = quicklist->tail = NULL;
    quicklist->len = 0;
    quicklist->count = 0;
    quicklist->compress = 0;
    // 默认为-2,表示ziplist的字节数最大不能超过8KB
    quicklist->fill = -2;
    quicklist->bookmark_count = 0;
    return quicklist;
}
添加元素

添加元素的时候可以在链表的头部或者尾部进行添加,以头部添加为例:

  1. 首先调用_quicklistNodeAllowInsert方法判断是否允许添加元素到ziplist,如果允许,调用ziplistPush方法进行添加
  2. 如果_quicklistNodeAllowInsert不允许添加元素,则需要新创建一个quicklistNode,然后将元素添加到新创建的quicklistNode的压缩列表中
// 从头部添加元素
int quicklistPushHead(quicklist *quicklist, void *value, size_t sz) {
    quicklistNode *orig_head = quicklist->head;
    // 判断是否允许添加
    if (likely(
            _quicklistNodeAllowInsert(quicklist->head, quicklist->fill, sz))) {
        // 将元素添加到ziplit
        quicklist->head->zl =
            ziplistPush(quicklist->head->zl, value, sz, ZIPLIST_HEAD);
        quicklistNodeUpdateSz(quicklist->head);
    } else {
        // 新创建quicklistNode节点
        quicklistNode *node = quicklistCreateNode();
        // 添加元素
        node->zl = ziplistPush(ziplistNew(), value, sz, ZIPLIST_HEAD);

        quicklistNodeUpdateSz(node);
        _quicklistInsertNodeBefore(quicklist, quicklist->head, node);
    }
    // 更新数量
    quicklist->count++;
    quicklist->head->count++;
    return (orig_head != quicklist->head);
}

_quicklistNodeAllowInsert

_quicklistNodeAllowInsert方法用于判断是否允许在某个quicklistNode指向的压缩列表中添加元素。

在quicklist的结构体定义中,fill指定了ziplist中能包含的最大元素个数或者ziplist最大的字节数,_quicklistNodeAllowInsert方法就是判断ziplist中的元素个数或者ziplist的字节数是否超过了限制:

// node:当前的quicklistNode节点
// fill:ziplist中能包含的最大元素个数或者ziplist最大的字节数
// sz:要添加元素的大小
REDIS_STATIC int _quicklistNodeAllowInsert(const quicklistNode *node,
                                           const int fill, const size_t sz) {
    if (unlikely(!node))
        return 0;

    int ziplist_overhead;
    /* 判断要添加元素的大小是否小于254 */
    if (sz < 254)
        ziplist_overhead = 1;
    else
        ziplist_overhead = 5;

    /* 判断要添加元素的大小是否小于64 */
    if (sz < 64)
        ziplist_overhead += 1;
    else if (likely(sz < 16384))
        ziplist_overhead += 2;
    else
        ziplist_overhead += 5;

    /* 计算添加元素后的当前的quicklistNode的大小 + 新加入元素的大小 + 插入元素后ziplit的prevlen占用大小 */
    unsigned int new_sz = node->sz + sz + ziplist_overhead;
    // 判断添加元素后的ziplist的字节数是否超过了fill中设置的大小
    if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(new_sz, fill)))
        return 1;
    else if (!sizeMeetsSafetyLimit(new_sz))
        return 0;
    else if ((int)node->count < fill) // 判断ziplist的元素个数是否超过了fill设置的大小
        return 1;
    else
        return 0;
}

总结

  1. 在Redis3.2版之前,Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis使用压缩列表实现,否则Redis使用双向链表实现。

  2. 为了解决压缩列表在节点多的时候查找效率低的问题以及连锁更新问题,在Redis3.2版之后引入了quicklist,quicklist是一个双向链表,链表中的每一个节点是一个ziplist。

  3. quicklist中限定了ziplist的大小,如果超过了限制的大小,新加入元素的时候会生成一个新的quicklistNode节点。

  4. quicklist通过限定ziplist的大小来保证一个ziplist中的元素个数不会太多,如果需要连锁更新,也只在某个quicklistNode节点指向的ziplist中更新,不会引发整个链表的更新,以此来解决压缩列表存在的问题。

参考

陈雷《Redis5设计与源码分析》

极客时间 - Redis源码剖析与实战(蒋德钧)

Redis版本:redis-6.2.5

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

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

相关文章

vue-devtools插件安装

拓展程序连接 链接&#xff1a;https://pan.baidu.com/s/1tEyZJUCEK_PHPGhU_cu_MQ?pwdr2cj 提取码&#xff1a;r2cj 一、打开谷歌浏览器&#xff0c;点击扩展程序-管理扩展程序 二、打开开发者模式&#xff0c;将vue-devtools.crx 拖入页面&#xff0c;点击添加扩展程序 成…

三、【色彩模式与颜色填充】

文章目录 Photoshop常用的几种颜色模式包括&#xff1a;1. RGB模式2. CMYK模式3. 灰度模式4. LAB模式5. 多通道模式 Photoshop颜色填充1.色彩基础2.拾色器认识3.颜色填充最后附上流程图&#xff1a; Photoshop常用的几种颜色模式包括&#xff1a; 1. RGB模式 详细可参考&…

mysql-sql执行流程

sql执行流程 MYSQL 中的执行流程 MYSQL 中的执行流程 sql 执行流程如下图

【Qt基础篇】信号和槽

文章目录 一些常见的bug&#xff1a;字符集不对产生的错误VS平台中文乱码 QT的优点关于.pro文件QtCreator快捷键最简单的qt程序按钮的创建对象模型**Qt窗口坐标**体系信号和槽机制connect函数系统自带的信号和槽案例&#xff1a;实现点击按钮-关闭窗口的案例 自定义信号和槽案例…

AWD常见防御加固手段

目录 一、加固用户名密码&#xff08;用户层&#xff09; 1、修改linux用户密码 2、删除其他可登录用户 二、加固SQL数据库&#xff08;服务层&#xff09; 1、修改mysql密码 2、删除匿名用户 3、刷新配置 4、改网站后台密码 三、后门文件查杀 四、关闭shell连接进程 …

安装rockylinux 9.2 版本虚拟机

下载rockylinux镜像 方法1&#xff1a;官网下载rockyliunx 方法2&#xff1a;阿里云镜像站下载 因为网络问题&#xff0c;我这里选择阿里云镜像站下载 VMware 安装Rckyliunx9.2版本虚拟机 或者 安装向导页面

LLM评估标准有哪些?

为了有效衡量和优化LLM的性能和泛化能力&#xff0c;并揭示其优势和局限&#xff0c;建立合理的LLM评价基准具有重要意义。现阶段&#xff0c;主流的LLM评估方法可划分为3类&#xff1a; 1&#xff09;人工评估。 基于人工的评估方法通常需要邀请大量的志愿者或相关领域专家对…

创意中秋与国庆贺卡 - 用代码为节日增添喜悦

目录 ​编辑 引言 贺卡的初始主题 - 中秋节 点击头像&#xff0c;切换至国庆主题 文本动画 用代码制作这个贺卡 获取完整代码&#xff08;简单免费&#xff09; 总结 引言 中秋佳节和国庆日是中国两个重要的传统节日&#xff0c;一个寓意团圆与祝福&#xff0c;另一个…

全网唯一!Matlab王者荣耀配色包MHonor

前些日子在家整理文档&#xff0c;偶然发现自己一年前建的一个工程&#xff0c;其大概内容是从王者荣耀一些角色皮肤的原画中提取配色方案&#xff0c;从而用于PPT制作、论文插图绘制等&#xff0c;为枯燥的科研生活增添点儿乐趣。 但是&#xff0c;由于自己当时的技术力还不够…

不讲故事的设计模式-责任链模式

文章目录 基本概念责任链模式标准结构责任链模式的扩展仿照Servlet Filter的实现方式 责任链模式的应用场景业务场景开源框架中的应用 责任链模式的缺点关于设计模式乱用的现象 基本概念 在责任链模式中可以定义多个处理节点&#xff08;Handler&#xff09;&#xff0c;当接收…

【从0开始配置前后端项目】——Docker环境配置

1. 准备一台纯净的服务器 镜像&#xff1a;CentOS 7.9 64位 CPU & 内存&#xff1a;2核2G 系统盘&#xff1a;60GB 峰值带宽&#xff1a;30Mbps 流量包&#xff1a;600GB / 600GB 2. 安装Docker 2.1 卸载旧的版本 $ sudo yum remove docker \docker-client \docker-cl…

芯片不是st公司,cmsis-dap调试器的使用

存在的问题&#xff1a; 分析&#xff1a;因为这块板子不是我们自己画的&#xff0c;也没细看芯片上的丝印&#xff0c;一开始我还以为芯片是盗版的&#xff0c;然后有人看到了丝印的前缀是GD&#xff0c;我们就意识到可能是芯片包没装对的问题了解决方法&#xff1a; &#xf…

互联网Java工程师面试题·Memcached篇·第一弹

目录 1、Memcached 是什么&#xff0c;有什么作用&#xff1f; 1.1 memcached 服务在企业集群架构中有哪些应用场景&#xff1f; 1.1.1 作为数据库的前端缓存应用 1.1.2 作业集群的 session 会话共享存储 2、Memcached 服务分布式集群如何实现&#xff1f; 3、Memcach…

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解)

目录 1、题目介绍 2、解题思路 2.1、暴力破解法 2.2、归并排序思想 2.2.1、画图详细讲解 2.2.2、归并排序解决逆序对的代码实现 1、题目介绍 首先阅读题目可以得出要点&#xff0c;即当前数大于后数时则当作一个【逆序对】&#xff0c;而题目是要求在一个数组中计算一共存…

专业综合课程设计 - 优阅书城项目(第一版)

此项目是《专业综合课程设计》带练项目 实现的功能有&#xff1a; 登录、注销、添加图书、删除图书、编辑图书 包含资源&#xff1a; 优阅书城&#xff08;bookstore&#xff09;源码 数据库数据 课程笔记 下载链接&#xff1a;https://wwpv.lanzoue.com/i79nx1av4doj 登录功…

小谈设计模式(20)—组合模式

小谈设计模式&#xff08;20&#xff09;—组合模式 专栏介绍专栏地址专栏介绍 组合模式对象类型叶节点组合节点 核心思想应用场景123 结构图结构图分析 Java语言实现首先&#xff0c;我们需要定义一个抽象的组件类 Component&#xff0c;它包含了组合节点和叶节点的公共操作&a…

两数之和(Hash表)[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个整数数组nums和一个整数目标值target&#xff0c;请你在该数组中找出"和"为目标值target的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元…

lv7 嵌入式开发-网络编程开发 12 IP协议与ethernet协议

目录 1 IP协议作用和意义 2 IP数据报首部格式 3 IP数据报分片 4 以太网协议作用和意义&#xff08;链路层&#xff09; 5 练习 1 IP协议作用和意义 IP网的意义 当互联网上的主机进行通信时&#xff0c;就好像在一个网络上通信一样&#xff0c;看不见互连的各具体的网络异…

Vue中如何进行分布式搜索与全文搜索(如Elasticsearch)

在Vue中实现分布式搜索与全文搜索&#xff08;使用Elasticsearch&#xff09; 分布式搜索和全文搜索在现代应用程序中变得越来越重要&#xff0c;因为它们可以帮助用户快速查找和检索大量数据。Elasticsearch是一种强大的分布式搜索引擎&#xff0c;它可以用于实现高性能的全文…

文举论金:非农到来!黄金原油全面走势分析策略独家指导

市场没有绝对&#xff0c;涨跌没有定势&#xff0c;所以&#xff0c;对市场行情的涨跌平衡判断就是你的制胜法宝。欲望&#xff01;有句意大利谚语&#xff1a;让金钱成为我们忠心耿耿的仆人&#xff0c;否则&#xff0c;它就会成为一个专横跋扈的主人。空头&#xff0c;多头都…