【Redis】深入理解 Redis 常用数据类型源码及底层实现(5.详解List数据结构)

本文是深入理解 Redis 常用数据类型源码及底层实现系列的第5篇~前4篇可移步( ̄∇ ̄)/

【Redis】深入理解 Redis 常用数据类型源码及底层实现(1.结构与源码概述)-CSDN博客

【Redis】深入理解 Redis 常用数据类型源码及底层实现(2.版本区别+dictEntry & redisObject详解)-CSDN博客

【Redis】深入理解 Redis 常用数据类型源码及底层实现(3.详解String数据结构)-CSDN博客

【Redis】深入理解 Redis 常用数据类型源码及底层实现(4.详解Hash数据结构)_查看 hash-max-ziplist-entries 命令-CSDN博客


正文开始~

在Redis 3之前,List数据结构底层ziplist和linkedlist双向链表(当列表对象中元素的长度比较小或者数量比较少的时候,采用ziplist来存储(内存紧凑,访问效率高,但是更新效率低,当数据量较大时,可能导致大量的内存复制)当列表对像中元素的长度比较大或者数据数量比较多的时候会使用linkedlist(修改效率高,但是内存开销大,当节点较多时,会产生大量的内存碎片)。

后续综合了两者的优缺点,使用quicklist替换了ziplist和linkedlist双向链表。

虽然都是quicklist,但其实在Redis 6及其以前和Redis 7及其以后也存在较大的不同。简单一句话来理解就是:Redis 6的quicklist中装的是ziplist而Redis 7的quicklist中装的是listpack(看过上一篇介绍Hash得文章的朋友应该了解listpack就是用来替代ziplist的)

我们可以对比下来看,首先是相关的配置参数

先看下都有的list-compress-depth和list-max-ziplist-size

  • list-compress-depth指的是压缩配置,表示一个quicklist两端不被压缩的节点个数(这里的节点是quicklist双向链表的节点,不是里面的ziplist/listpack)
    • 取值含义:
      • 0:默认值,表示都不压缩
      • n:quicklist两端各有n个节点不被压缩(中间的都压缩,n=1/2/3……)
  • list-max-ziplist-size指的是ziplist中的entry的配置
    • 取值含义:
      • 正值:表示按照数据项个数来限定每个quicklist节点上的ziplist的长度(例如取5的时候,表示每个quicklist节点的ziplist最多包含5个数据项)
      • 负值:表示按照占用字节数来限定每个quicklist节点上的ziplist长度
        • 取值含义(只能取-5/-4/-3/-2/-1五个值)
          • -5:每个quicklist节点上的ziplist大小不能超过64Kb(1kb=1024 bytes,即64*1024 bytes)
          • -4:每个quicklist节点上的ziplist大小不能超过32Kb(1kb=1024 bytes,即32*1024 bytes)
          • -3:每个quicklist节点上的ziplist大小不能超过16Kb(1kb=1024 bytes,即16*1024 bytes)
          • -2:默认值,每个quicklist节点上的ziplist大小不能超过8Kb(1kb=1024 bytes,即8*1024 bytes)
          • -1:每个quicklist节点上的ziplist大小不能超过4Kb(1kb=1024 bytes,即4*1024 bytes)

而Redis 7多了一个参数list-max-listpack-size,这个参数的含义跟list-max-ziplist-size基本一致,不过指的不是ziplist中的entry,而是listpack中的entry的配置

  • 取值含义:
    • 正值:表示按照数据项个数来限定每个quicklist节点上的listpack的长度(例如取5的时候,表示每个quicklist节点的listpack最多包含5个数据项)
    • 负值:表示按照占用字节数来限定每个quicklist节点上的ziplist长度
      • 取值含义(只能取-5/-4/-3/-2/-1五个值)
        • -5:每个quicklist节点上的listpack大小不能超过64Kb(1kb=1024 bytes,即64*1024 bytes)
        • -4:每个quicklist节点上的listpack大小不能超过32Kb(1kb=1024 bytes,即32*1024 bytes)
        • -3:每个quicklist节点上的listpack大小不能超过16Kb(1kb=1024 bytes,即16*1024 bytes)
        • -2:默认值,每个quicklist节点上的listpack大小不能超过8Kb(1kb=1024 bytes,即8*1024 bytes)
        • -1:每个quicklist节点上的listpack大小不能超过4Kb(1kb=1024 bytes,即4*1024 bytes)

看张比较形象的图

quicklist.h

在quicklist.h的源代码中,我们可以看到每个节点被封装成了quicklistNode对象

typedef struct quicklist {quicklistNode *head;quicklistNode *tail;unsigned long count;        /* total count of all entries in all ziplists */unsigned long len;          /* number of quicklistNodes */int fill : QL_FILL_BITS;              /* fill factor for individual nodes */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:双向链表的长度(quicklistNode的数量)
  • compress:压缩深度(默认0表示不压缩)

不知道有没有小伙伴觉得奇怪,这些参数都没见到ziplist,但是为什么count表示的是ziplist中存放的元素个数?

那是因为在每个quicklistNode对象中,装着一个ziplist

typedef struct quicklistNode {struct quicklistNode *prev;struct quicklistNode *next;unsigned char *zl;unsigned int sz;             /* ziplist size in bytes */unsigned int count : 16;     /* count of items in ziplist */unsigned int encoding : 2;   /* RAW==1 or LZF==2 */unsigned int container : 2;  /* NONE==1 or ZIPLIST==2 */unsigned int recompress : 1; /* was this node previous compressed? */unsigned int attempted_compress : 1; /* node can't compress; too small */unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;

我们解释下关键参数:

  • *prev:指向前一个节点的指针
  • *next:指向后一个节点的指针
  • *zl:指向实际存储数据的ziplist
  • sc:当前ziplist占用的字节数
  • count:当前ziplist中存放的元素数(最大65536)
  • encoding:表示采用的压缩算法(1:RAW、2:LZF)

结构图解

接下来我们看下当执行新增元素操作时,源码的底层代码逻辑

Redis 6和Redis 7pushGenericCommand()方法略有不同(其实主要就是listpack替代ziplist的区别)

搞定🎉~~~~

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

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

相关文章

BeautifulSoup+xpath+re+css简单复习+新的scrapy的学习

1.BeautifulSoupsoup BeautifulSoup(html,html.parser)all_icosoup.find(class_"DivTable") 2.xpath trs resp.xpath("//tbody[idcpdata]/tr") hong tr.xpath("./td[classchartball01 or classchartball20]/text()").extract() 这个意思是找…

基于RabbitMQ的RPC通信

基于RabbitMQ的RPC通信 版本信息操作步骤搭建RabbitMQ(默认用户名:guest 密码:guest )服务端实现(srv.py)客户端实现(client.py)性能测试(4919 qps) 当需要调用局域网中的服务时,可以用frp进行穿透,也可以在公网搭建RabbitMQ服务器做消息中转,本文演示了这个步骤。 版本信息 …

文件拖放到窗体事件

网上的实现1 实现结果 具体实现代码:注意需要使能允许拖拽 public partial class Form1 : Form {public Form1(){InitializeComponent();this.AllowDrop true; //允许拖拽}private void Form1_DragEnter(object sender, DragEventArgs e){this.Text DateTime.No…

一键安装|卸载 mysql 8.2.0 shell脚本

场景:为了在无网、外网 mysql 安装方便,这里分享一个自己编写得 shell脚本 这里以当前最新版 mysql 8.2.0;centos-7 二进制包下载: 下载地址 mysql_install.sh #!/bin/bash # 解压安装包 tar -xf mysql-8.2.0-linux-glibc2.17-x8…

GO语言学习笔记(与Java的比较学习)(三)

函数 按值传递(call by value) 按引用传递(call by reference) Go 默认使用按值传递来传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行更改,但不…

TC3xx SMU、PMIC和Tranceiver的功能安全闭环

目录 1.TLF35584安全状态输出响应对象 1.1 响应ERR 收集到的错误信号 1.2 响应监控功能引发的ROT 1.3 响应看门狗引发的错误 1.4 环境过温引发的错误状态 1.5 为什么设计SSx? 2. 安全状态输出给谁 3.小结 在之前文章里,我们简述了TC3xx SMU如何…

npm install常见错误的完整指南

目录 1. ERR! Error: EACCES2. ERR! ENOENT3. ERR! network timeout4. ERR! Maximum call stack size exceeded5. ERR! Failed at the xxxxxx install script6. ERR! code EINTEGRITY7. ERR! Please try running this command again as root/Administrator8. ERR! code ELIFECY…

尚硅谷(SpringCloudAlibaba微服务分布式)学习代码Eureka部分

1.项目结构 2.cloud2024 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.a…

ERPNext v14在ubuntu22上安装配置的完整过程

注意:在配置ERPNext之前,我是用virtualbox配置了好多次ubuntu22.04操作系统,一路都很通畅,唯独重启操作系统后,就会出现黑屏的现象。期间尝试了更改显存大小、内存大小、磁盘大小,甚至一度怀疑是自己电脑或者ubuntu22.04的镜像问题等等,一直未解决。真正的原因竟然是vir…

面试笔记系列六之redis+kafka+zookeeper基础知识点整理及常见面试题

Redis redis持久化机制&#xff1a;RDB和AOF Redis 持久化 Redis 提供了不同级别的持久化方式: RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redi…

IPD(集成产品开发)—核心思想

企业发展到一定阶段就会遇到管理瓶颈&#xff0c;IPD流程是一种高度结构化的产品开发流程&#xff0c;它集成了业界很多优秀的产品开发方法论&#xff0c;像搭积木一样的组合成一种非常有效的流程。如果我们能根据企业的规模和行业特点&#xff0c;对全流程的IPD进行合适的裁剪…

Dell R730 2U服务器实践1:开机管理

新入手一台Dell R730 2U服务器&#xff0c;用来做FreeBSD下的编译工作和Ubuntu下简单的AI学习和调试。 服务器配置&#xff1a; CPU&#xff1a;E5 2680V4 2 14核心 内存&#xff1a;DDR4 ECC 16G2 2133 MHz 网卡&#xff1a;双千双万 Intel(R) 2P X540/2P I350 rNDC 硬盘…

html2canvas + JsPDF.js 导出pdf分页时的问题

问题描述 前一段时间 实现了html2canvas jspdf.js 导出pdf的功能 项目当时没有测试做完就先搁置 最近项目要上线发现分页时问题 这篇文章记录一下之前的bug import html2canvas from html2canvas; import JsPDF from jspdf export function savePdf(el, title) {html2canva…

能源计量器具的种类划分

能源计量器具是指测量对象为一次能源、二次能源和载能工质的计量器具。 1.能源计量器具的分类 (1)按结构特点分类。 量具&#xff0c;用固定形式复现量值的计量器具&#xff0c;如量块、砝码标准电池、标准电阻、竹木直尺、线纹米尺等。 计量仪器仪表&#xff0c;将被测量的量…

What to Look for When Evaluating Middleware for Integration

Game Engine Gem 1 1.1 我们该如何对待中间件 现代游戏很少有完全由内部开发人员编写的专有定制代码组成的作品。在游戏行业中竞争所需的大量精良功能&#xff0c;对于一个工作室来说简直就是一项艰巨的任务&#xff0c;用一句话概括就是 "无利可图"。如今&#xff0…

Google checkstyle实战

概述 CheckStyle检查代码是否符合制定的规范。CheckStyle检查是基于源码的&#xff0c;无需编译&#xff0c;执行速度快。 CheckStyle的主要流程是&#xff1a; 对Java文件进行词法语法分析&#xff0c;生成语法树。载入配置文件&#xff08;checkstyle-metadata.xml以及自定…

JAVA调用lua脚本

一、依赖包 <dependency><groupId>org.luaj</groupId><artifactId>luaj-jse</artifactId><version>3.0.1</version></dependency> 二、代码示例 // 脚本函数可以存在字符串中String formula "function ntc(n) return 2…

软考高级系统分析师:数据库知识点数据库的范式和例题

一、AI 解读 数据库范式是一组规则&#xff0c;用于指导数据库设计&#xff0c;以减少数据冗余、提高数据完整性&#xff0c;并支持更有效的数据处理。下面是几个常见的数据库范式&#xff0c;我将用通俗易懂的语言和示例来帮助你理解它们&#xff1a; 第一范式&#xff08;1…

【ElfBoard】基于 Linux 的智能家居小项目

大家好&#xff0c;我是 Hello阿尔法&#xff0c;这段时间参与了保定飞凌嵌入式技术有限公司举办的 ElfBoard 共创社招募活动&#xff0c;并有幸成为了一名共创官&#xff0c;官方寄来了一块 ELF 1 开发板&#xff0c;开箱看这里 ELF 1 开箱初体验。 作为共创官&#xff0c;我…

C语言实现班级事务管理系统

班级事务管理系统采用C语言实现&#xff0c;可以用于课程设计和学习&#xff0c;代码有两个文件&#xff1a;班级事务管理系统.cpp和辅助操作.cpp。 班级事务管理系统.cpp代码如下&#xff1a; #include <stdio.h> #include <time.h> #include <conio.h> #…