四、Redis五种常用数据类型-List

news2025/1/16 17:04:14

List是Redis中的列表,按照插入顺序保存数据,插入顺序是什么样的,数据就怎么保存。可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含232-1个元素(4294967295,每个列表超过40亿个元素)。是一种双向列表结构。

1、List列表命令

  • blpop key1[key2…] timeout:从头部(左边)移出并获取一个元素,如果列表没有元素会阻塞到列表有元素或者超时。
  • brpop key1[key2…] timeout:从尾部(右边)移出并获取一个元素,如果列表没有元素会阻塞到列表有元素或者超时。
  • brpoplpush source destination timeout:从尾部(右边)移出一个元素,并添加到另一个列表的头部并返回。如果列表没有元素会阻塞到列表有元素或者超时。
  • lindex key index:通过索引(下标)获取列表中的元素。index可以为负,-1表示最后一个元素,-2表示倒数第二个元素。以此类推
  • linsert key before|after pivot value:将值value插入到列表key中,位于pivot之前或者之后。

当指定的元素不在列表或者列表为空时不执行任何操作,如果key不是列表类型,则返回一个错误

  • llen key:获取列表的长度
  • lpop key:从列表的头部(左边)移出并获取列表一个元素。如果列表没有元素,不会阻塞。
  • lpush key value1[value2]:将一个或者多个值插入到列表头部(左边)。多个元素一起插入时,后面的头部。

如果插入的key不存在,将创建一个空的列表,并执行lpush操作。当key不是列表类型时,会报错。

  • lpushx key value:将一个值插入到列表的头部(左边),当列表不存在时操作无效。
  • lrange key start end:返回列表中指定区间的元素,从0开始,当end为-1时表示到最后一个元素,-2为倒数第二个元素。
  • lren key count value:移出列表中值和value相等的值。

count的值有如下几种情况:

  • count>0:从列表的头部(左)到尾部(右)搜索,移出值与value相等的元素,数量为count。
  • count<0:从列表的尾部(右)到头部(做)搜索,移出值与value相等的元素,数量为count的绝对值。
  • count=0:移出列表中所有与value相等的元素。
  • lset key index value:通过索引(下标)设置元素的值。当下标超出范围(超过列表的已有数量)或者列表为空,进行lset操作会报错。
  • ltrim key start end:对一个列表进行修剪,让列表只存在指定区间内的元素,以外的全删除。0表示第一个元素,1表示第二个,-1表示最后一个,-2表示倒数第二个。以此类推。
  • rpop key:移出列表的最后一个元素(最右边)。不会阻塞。
  • rpoplpush source destination:移出source列表的最后一个元素,插入到destination的头部,并返回。
  • rpush key value1[value2]:在列表尾部添加一个或者多个元素。后边的在最后。
  • roushx key value:将值添加到已存在列表的尾部。

2、底层结构

2.1、linkedList

Java中的LinkedList类似,Redis中的linkedList是一个双向链表,也是由一个个的节点组成。Redis借助c语言的链表节点结构如下:

typedf struct listNode{
	//前一个节点
    struct listNode *prev;
    //后一个节点
    struct listNode *next;
    //当前节点的值的指针
    void *value;
}listNode;

prev指向前一个节点,next指向下一个节点,value保存着当前节点对应的数据对象。listNode结构示意图如下:
image.png
链表的结构如下:

typedf struct list{
	//头指针
    listNode *head;
    //尾指针
    listNode *tail;
    //节点拷贝函数
    void *(*dup)(void *ptr);
    //释放节点函数
    void *(*free)(void *ptr);
    //判断两个节点是否相等函数
    int (*match)(void *ptr,void *key);
    //链表长度
    unsigned long len;
}list;

head指向链表的头结点,tail指向链表的尾节点。len表示链表有多少个节点,这样可以在O(1)的时间复杂度内获得链表的长度。
链表的结构示意图如下:
image.png

2.2、zipList

Redis的zipList结构如下:

typedf struct ziplist<T>{
    //压缩列表占用字符数
    int32 zlbytes;
    //最后一个元素距离起始位置的偏移量,用于快速定位最后一个节点
    int32 zltail_offset;
    //元素个数
    int16 zllength;
    //元素内容
    T[] entries;
    //结束位 0xFF
    int8 zlend;
}ziplist

zipList结构示意图如下:
image.png
根据zltail_offset字段就可以快速定位到最后一个entry的位置,这样配合Entry结构中的prelen字段,就可以实现链表的倒序遍历。
下面是entry的结构:

typed struct entry{
	//前一个entry的长度
    int<var> prelen;
    //元素编码类型
    int<var> encoding;
    //元素内容
    optional byte[] content;
}entry

prelen保存了前一个entry的长度,这样就可以在倒序遍历时就可以根据此字段来获取到前一个entry的位置。encoding保存了content内容的编码类型。content是保存的内容,其类型是optional,表示这个字段是可选的。当content是很小的整数时,他会内连到content的尾部。entry结构示意图如下:
image.png
思考题:为什么有了**linkedList**还要设计一个**zipList**呢?

  • 就像zipList的名字一样,他是一个压缩列表,相比较于linkedList,其少了prenext两个指针。Redis中两个指针就要占用16个字节(64位操作系统的一个指针就是8字节)。
  • linkedList每个节点的内存都是单独分配,加速了内存的碎片化,影响内存的管理。
  • zipList的内存都是连续组成的,这样一来,由于内存是连续就减少了许多内存的碎片化和指针的内存占用。

zipList遍历时,先根据zlbyteszltail_offset定位到最后一个entry的位置,然后根据最后一个entryprelen确定前一个entry的位置。

连锁更新

前面说到,Entry结构中有个prelen字段,表示其前一个entry的长度,他的长度要么是1个字节,要么是5个字节:

  • 前一个entry的长度小于254字节,则prelen的长度为1字节(8位,最大可表示255);
  • 前一个entry的长度大于254字节,则prelen的长度为5字节;

假设有一组压缩列表的长度都在250~253之间,突然增加一个entry长度大于254字节。由于新的entry的长度大于254字节,那么原链表的首节点的prelen的长度就会为5个字节,随后会导致其他的所有entryprelen都增大为5个字节,每次prelen的增大,都需要一次内存的再分配操作。
image.png

linkedList和zipList的对比
  • 当列表的长度或者数量较少时,通常采用zipList,当列表的长度较大或者数量较多时,通常采用linkedList存储。
  • 双向链表linkedList方便与在列表上增加或者删除操作,也即pushpop操作。但是其内存的开销比较大。一方面其比zipList多了两个指针。且其每个节点的内存都是独立的,地址不连续,容易形成内存碎片。
  • zipList存储在一块连续的内存上,其查询速度较快,但是不利于修改操作,插入和删除操作需要频繁的申请和释放内存。特别是当zipList很大时,一次realloc可能会导致大量的拷贝。

2.3、quickList

Redis3.2版本后,list的底层实现又多了一种,quickListquickListzipListlinkedList的混合体,它将linkedList按段切分,每一段使用zipList来存储数据。每个quickList之间用双向指针串接起来。示意图如下:
image.png
节点quickList结构如下:

typedf struct quicklistNode{
	//前一个节点
    quicklistNode *prev;
    //后一个节点
    quicklistNode *next;
    //压缩列表
    ziplist* zl;
    //ziplist大小
    int32 size;
    //ziplist中元素数量
    int16 count;
    //编码形式 存储ziplist还是LZF压缩存的ziplist
    int2 encoding;
    ...
}quicklistNode;

quickList的结构如下:

typedf struct quicklist{
	//头节点
    quicklistNode* head;
    //尾节点
    quicklistNode* tail;
    //元素总数
    long count;
    //quicklistNode节点总数
    int nodes;
    //压缩深度算法
    int compressDepth;
    ...
}quicklist;

为了进一步节约空间,Redis还会对ziplist进行压缩存储,使用LZF算法进行压缩,可以选择压缩深度。

每个zipList可以存储元素的个数

Redis.conf文件,在DVANCE CONFIG下面有着清晰记载:

# Lists are also encoded in a special way to save a lot of space.
# The number of entries allowed per internal list node can be specified
# as a fixed maximum size or a maximum number of elements.
# For a fixed maximum size, use -5 through -1, meaning:
# -5: max size: 64 Kb  <-- not recommended for normal workloads
# -4: max size: 32 Kb  <-- not recommended
# -3: max size: 16 Kb  <-- probably not recommended
# -2: max size: 8 Kb   <-- good
# -1: max size: 4 Kb   <-- good
# Positive numbers mean store up to _exactly_ that number of elements
# per list node.
# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size),
# but if your use case is unique, adjust the settings as necessary.
list-max-ziplist-size -2

quicklist内部默认单个ziplist的长度为8K字节,即list-max-ziplist-size的值设置为-2,超出这个阈值,就会重新生成一个新的ziplist来存储数据。根据注释可知,性能最好的时候就是list-max-ziplist-size为-1和-2时,即分别是4Kb和8Kb。当然这个值也可以是正数,当值为正数n时,表示每个quicklist上的ziplist最多包含n个数据项。

压缩深度

quickList中可以使用压缩算法对zipList进行进一步的压缩,这个算法就是LZF算法,这是一种无损压缩算法。使用压缩算法对zipList进行压缩后,zipList结构如下:

typedf struct zoplist_compressed{
	//元素个数
    int32 size;
    //元素内容
    byte[] compressed_data;
}

压缩后的quickList结构如下:
image.png
Redis.conf配置文件中对其进行配置

# Lists may also be compressed.
# Compress depth is the number of quicklist ziplist nodes from *each* side of
# the list to *exclude* from compression.  The head and tail of the list
# are always uncompressed for fast push/pop operations.  Settings are:
# 0: disable all list compression
# 1: depth 1 means "don't start compressing until after 1 node into the list,
#    going from either the head or tail"
#    So: [head]->node->node->...->node->[tail]
#    [head], [tail] will always be uncompressed; inner nodes will compress.
# 2: [head]->[next]->node->node->...->node->[prev]->[tail]
#    2 here means: don't compress head or head->next or tail->prev or tail,
#    but compress all nodes between them.
# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]
# etc.
list-compress-depth 0

list-compress-depth这个参数表示一quickList**两端不被压缩的节点个数,**实际上这里的节点个数指的是quickList的节点个数,而不是zipList里面的数据项个数。

  • quickList默认的压缩深度为0,也就是不开启压缩。
  • list-compress-depth为1时,表示首尾各有一个节点不进行压缩,中间节点进行压缩。
  • list-compress-depth为2时,表示首尾各有两个节点不行压缩,中间节点进行压缩。
  • 以此类推。

从上面可以看到quickList的首尾两个节点永远不会被压缩。

3、总结

image.png

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

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

相关文章

如何获取中国各省市区的边界

前几个专栏我介绍了获取各流域边界的方法&#xff0c;可参见以下的文章&#xff1a; 格林兰岛和南极洲的流域边界文件下载-CSDN博客 读取shp文件中的经纬度坐标-CSDN博客 读取谷歌地球的kml文件中的经纬度坐标_谷歌地球识别穿过矿区的公路,并获取公路的经纬度坐标-CSDN博客 关于…

图像处理:图像噪声添加

文章目录 前言一、高斯噪声二、椒盐噪声三、泊松噪声四、斑点噪声五、指数噪声六、均匀噪声总结 前言 本文主要介绍几种添加图像噪声的方法&#xff0c;用于数据增强等操作。 以下图为例。 一、高斯噪声 高斯噪声就是给图片添加一个服从高斯分布的噪声&#xff0c;可以通过调…

OpenGL 入门(三)—— OpenGL 与 OpenCV 共同打造大眼滤镜

从本篇开始&#xff0c;会在上一篇搭建的滤镜框架的基础上&#xff0c;介绍具体的滤镜效果该如何制作。本篇会先介绍大眼滤镜&#xff0c;先来看一下效果&#xff0c;原图如下&#xff1a; 使用手机后置摄像头对眼部放大后的效果&#xff1a; 制作大眼滤镜所需的主要知识点&…

Qt应用开发(拓展篇)——图表 QChart

一、前言 QChart是一个图形库模块&#xff0c;它可以实现不同类型的序列和其他图表相关对象(如图例和轴)的图形表示。要在布局中简单地显示图表&#xff0c;可以使用QChartView来代替QChart。此外&#xff0c;线条、样条、面积和散点序列可以通过使用QPolarChart类表示为极坐标…

PRL:新型量子传感方案突破纳米测量极限

朴茨茅斯大学的研究人员近期宣布了一项令人振奋的量子传感方案&#xff0c;该方案在测量两个干涉光子之间的横向位移方面达到了前所未有的量子灵敏度。 这一技术的突破为超分辨率成像技术带来了新的可能性。目前&#xff0c;这些技术通常采用单光子源作为探针&#xff0c;用于在…

无刷电机和有刷电机的区别

无刷电机和有刷电机的区别 无刷电机的定子上绕着线圈&#xff0c;线圈通常是成对出现的&#xff0c;通过控制电路为每一对线圈按照一定顺序输入电流&#xff0c;就可以产生旋转的磁场 它还有一个永磁体转子&#xff0c;现在多采用高磁能级的稀土铷铁硼材料&#xff0c;体积更小…

Python练习(函数)

目录 6-1 使用函数求素数和 函数接口定义&#xff1a; 裁判测试程序样例&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 6-2 使用函数输出指定范围内Fibonacci数的个数 函数接口定义&#xff1a; 裁判测试程序样例&#xff1a; 输入样例&#xff1a; 输出样…

【AI绘画】Midjourney 工笔画 水蓝色衣服的少女

using Midjourney 提示词&#xff1a; highly detailed,细节刻画细腻,超高清晰度,32k,HD,大师作品,高质量,动漫少女,水墨人像,20岁年轻身材很好的中国少女,惊人的美貌,五官精致,精致的妆容,华丽的水蓝色衣服,古风服饰,华丽的珠宝,飞扬的黑色长发,大风吹起头发,宝石发光,黄金装饰…

tf2使用savemodel保存之后转化为onnx适合进行om模型部署

tf2使用savemodel保存之后转化为onnx适合进行om模型部署 tf保存为kears框架h5文件将h5转化为savemodel格式&#xff0c;方便部署查看模型架构将savemodel转化为onnx格式使用netrononnx模型细微处理代码转化为om以及推理代码&#xff0c;要么使用midstudio tf保存为kears框架h5文…

Windows注册表

注册表 一.概述 注册表&#xff08;Registry&#xff09;是Microsoft Windows中的一个重要的数据库&#xff0c;用于[存储系统]和[应用程序]的设置信息。早在[Windows 3.0]推出[OLE]技术的时候&#xff0c;注册表就已经出现。随后推出的[Windows NT]是第一个从系统级别广泛使…

IT项目管理 选择/判断 【太原理工大学】

第一章、IT项目管理 判断题 1、搬家属于项目。&#xff08; 对 &#xff09; 2、项目是为了创造一个唯一的产品或提供一个唯一的服务而进行的永久性的努力。&#xff08; 错 &#xff09; 3、项目具有临时性的特征。&#xff08; 对 &#xff09; 4、项目开发过程…

基于RTI Connext使用Simulink的DDS Blockset

MathWorks一直是数据分发服务&#xff08;DDS&#xff09;标准的长期支持者。RTI Connext基于DDS&#xff0c;已与Simulink集成多年&#xff0c;使用户能够导入数据进行更逼真的模拟工作。 2021年&#xff0c;MathWorks通过其新推出的Simulink附加产品DDS Blockset提高了标准。…

怎么制作好玩的gif?试试这个工具轻松制作

视频之所以受大众的喜爱是因为有声音、画面的搭配&#xff0c;让观者深入其中体验感会更强。但是视频的体积较大、时长也比较长&#xff0c;给我们的传播和保存造成了一定的影响。那么&#xff0c;我们可以将视频制作成gif图片来使用&#xff0c;不需要下载软件&#xff0c;使用…

在哪个网站找视频素材?在哪可以下视频素材?

在这个视频内容极为重要的时代&#xff0c;高质量的视频素材成为了创作的关键。特别是4K和无水印视频素材&#xff0c;它们不仅提升了视觉效果&#xff0c;也为作品增加了专业度。以下是一些优秀的国内外视频素材网站&#xff0c;希望能助您一臂之力。 1. 蛙学府 专注于为中国…

01-基本概念- 索引,文档和 REST API

# kibana_sample_data_ecommerce 为es 索引#查看索引相关信息 GET kibana_sample_data_ecommerce#查看索引的文档总数 GET kibana_sample_data_ecommerce/_count#查看前10条文档&#xff0c;了解文档格式 POST kibana_sample_data_ecommerce/_search { }#_cat indices API #查看…

福州网站建设如何设计极简风格合理?

福州网站建设如何设计极简风格合理&#xff1f;企业网站逐渐流行&#xff0c;每个人的审美也发生着巨大的改变&#xff0c;开始追求一种极简的风格。简单的 风格才能够凸显原有的主题&#xff0c;不会太过主次不分。 越来越多的网站建设中选择极简的风格&#xff0c;简单的页面…

8款好用的电脑监控软件分享丨好资源不私藏!

电脑已经成为我们日常生活和工作的重要工具。随之而来的是&#xff0c;电脑监控的需求也逐渐增加。为了帮助大家更好地管理和监控电脑使用情况&#xff0c;本文将为您推荐8款好用的电脑监控软件。这些软件功能强大&#xff0c;易于使用&#xff0c;适用于各种场景&#xff0c;让…

什么情况下 MySQL 连查询都能被阻塞?

MySQL 的锁也是不少&#xff0c;在哪种情况下会连查询都能被阻塞&#xff1f;这是一个有意思的问题。 工作中&#xff0c;很多开发和 DBA 可能接触较多的锁也就行锁了。对于行锁&#xff0c;阻塞写能理解&#xff0c;阻塞读实在是想不到。能阻塞读的那肯定是颗粒度更大的锁了&…

电脑怎么压缩图片?压缩图片并不难

电脑怎么压缩图片&#xff1f;随着数字时代的来临&#xff0c;我们每天都在与大量的图片打交道&#xff0c;无论是社交媒体上的个人照片&#xff0c;还是工作中的设计图片&#xff0c;或是网页上的广告图片。然而&#xff0c;高质量的图片往往意味着大文件大小&#xff0c;这不…

如何将jsp项目转成springboot项目

昨天说过&#xff0c;springboot推荐使用Thymeleaf作为前后端渲染的模板引擎&#xff0c;为什么推荐用Thymeleaf呢&#xff0c;有以下几个原因&#xff1a; 动静结合&#xff1a;Thymeleaf支持HTML原型&#xff0c;允许在HTML标签中增加额外的属性来实现模板与数据的结合。这样…