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

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

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

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

相关文章

pytorch实现transformer(1): 模型介绍

文章目录 1. transformer 介绍2 Position Encoding2.1 位置编码原理2.2 代码实现3 Self-attention4 前馈层FFN5 残差连接与层归一化6 编码器和解码器结构1. transformer 介绍 Transformer 模型是由谷歌在 2017 年提出并首先应用于机器翻译的神经网络模型结构。机器翻译的目标是…

数字化校园的发展阶段

现代化技能虽然能很大程度上给人们日子带来很大的便利&#xff0c;可是许多新兴的科技被人们所接纳需求一个按部就班的进程。数字化学校也是如此。把高新科技引入到学校中&#xff0c;完全推翻之前的教育形式&#xff0c;关于学校来说也是一个巨大的挑战。所以数字化学校也不可…

怿星 × NI丨联合成功打造行业领先的L4自动驾驶数据回灌系统

怿星NI 联合成功打造行业领先的L4自动驾驶数据回灌系统&#xff08;终版&#xff09; 怿星与于NI&#xff08;恩艾&#xff09;公司联合打造的L4自动驾驶数据回灌系统&#xff0c;在支持多种数据同步回灌、实时模拟故障、高带宽数据传输的同时&#xff0c;具有视频链路扩展性高…

2024年钉钉群直播回放怎么保存

钉钉群直播回放下载插件我已经打包好了&#xff0c;有需要的自己下载一下 小白钉钉工具打包链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1234 --来自百度网盘超级会员V10的分享 1.首先解压好我给大家准备好的压缩包 2.再把逍遥一仙下载器解压出来&#xff0…

护眼台灯什么牌子好一点?五款专业护眼灯品牌排行分享

台灯作为家庭中不可或缺的桌面照明设备&#xff0c;在儿童和青少年的学习生活中扮演着至关重要的角色。对于这个年龄段的孩子来说&#xff0c;台灯的选择尤为关键&#xff0c;因为不恰当的照明可能对他们娇嫩的视力造成损害。护眼台灯什么牌子好一点&#xff1f;家长们在挑选台…

ERROR 1045 (28000) Access denied for user ‘root‘@‘IP‘(using password YES/NO)

查看权限 要查看MySQL用户的权限&#xff0c;您可以使用SHOW GRANTS语句。这将列出用户的权限&#xff0c;包括授予的权限和可以授予其他用户的权限。 以下是查看当前用户权限的SQL命令&#xff1a; SHOW GRANTS; 如果您想查看特定用户的权限&#xff0c;可以使用以下命令&…

delphi6直连redis服务(用lua脚本redis模块)

一、创建一个exe程序 创建一个exe程序,引用LuaRedis.pas单元(此单元自己封装的代码,目前主要封装了获取key和设置key/value功能),代码如下: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;type…

仅为娱乐,Python中如何重定义True为False?

在Python中&#xff0c;True 和 False 是内建的布尔常量&#xff0c;分别代表逻辑上的真和假。它们是不可变的&#xff0c;且在Python语言规范中具有特殊地位&#xff0c;不能被用户直接重定义。尝试给 True 或 False 赋予新的值是违反Python语言规则的&#xff0c;这样的操作会…

​在英特尔至强 CPU 上使用 Optimum Intel 实现超快 SetFit 推理

在缺少标注数据场景&#xff0c;SetFit 是解决的建模问题的一个有前途的解决方案&#xff0c;其由 Hugging Face 与Intel 实验室以及UKP Lab合作共同开发。作为一个高效的框架&#xff0c;SetFit 可用于对Sentence Transformers模型进行少样本微调。 SetFit 仅需很少的标注数据…

【JavaEE精炼宝库】计算机是如何工作的

目录 前言&#xff1a; 一、冯诺依曼体系 二、CPU基本知识 2.1 硬盘|内存|CPU关系&#xff1a; 2.2 指令&#xff1a; 2.3 CPU是如何执行指令的&#xff08;重点&#xff09;&#xff1a; 2.4 小结&#xff1a; 三、编程语言 3.1 程序&#xff1a; 3.2 编程语言发展&a…

游戏全自动打金搬砖,单号收益300+ 轻松日入1000+

详情介绍 游戏全自动打金搬砖&#xff0c;单号收益300左右&#xff0c;多开收益更多&#xff0c;轻松日入1000 可矩阵操作。 项目长期稳定&#xff0c;全自动挂机无需人工操作&#xff0c;小白&#xff0c;宝妈&#xff0c;想做副业的都可以。

【链表-双向链表】

链表-双向链表 1.链表的分类1.1 分类依据1.2 常用类型 2.双向链表的2.1 双向链表的结构2.2 双向链表的操作2.2.1 **初始化**2.2.2 **尾插**2.2.3 **头插**2.2.4 **尾删**2.2.5 **头删**2.2.6 在pos位置之后插入数据2.2.7 删除pos节点2.2.8 查找2.2.9 销毁 1.链表的分类 1.1 分…

翻译技巧早操练-(减译法)

hello&#xff0c;大家好&#xff0c;今天继续来学习翻译的技巧篇第二个-减译法。 往期回顾 翻译早操练-&#xff08;增译法&#xff09;-CSDN博客 减译法的目的就是为了译入语表达的通顺&#xff0c;如果原文的一些表达直接翻译到译入语即累赘还不合时宜&#xff0c;那么可以采…

【启明智显技术分享】基于ESP32-S3方案的彩屏固件烧录指南

前言&#xff1a; 【启明智显】专注于HMI&#xff08;人机交互&#xff09;及AIoT&#xff08;人工智能物联网&#xff09;产品和解决方案的提供商&#xff0c;我们深知彩屏显示方案在现代物联网应用中的重要性。为此&#xff0c;我们一直致力于为客户提供彩屏显示方案相关的技…

主播美颜技术探秘:计算机视觉赋能的直播美颜SDK

今天&#xff0c;我们将深入探讨直播美颜技术背后的计算机视觉原理&#xff0c;以及赋能这一技术的直播美颜SDK。 一、计算机视觉与直播美颜 计算机视觉是一门研究如何使机器“看”的学科&#xff0c;它利用数字图像处理和模式识别等技术&#xff0c;使计算机能够模拟人类视觉…

STL速查

容器 (Containers) 图解容器 支持随机访问 stringarrayvectordeque支持支持支持支持 string 类 构造函数 string(); ------创建一个空的字符串 例如: string str;string(const char* s); ------使用字符串s初始化string(const string& str); ------拷贝构造 赋值操作…

打破次元壁!Stable Diffusion将现实影像转成二次元动画,推特转赞10k+,网友:都可以重做《神奇宝贝》动漫了

破次元壁计划已启动&#xff01; 就在最近&#xff0c;有网友分享了一个用Stable Diffusion打造二次元动画的工具&#xff0c;直接在网上爆火。 先快来看一波效果。 万物皆可妙化为二次元&#xff0c;耳机也可蜕变成小兔兔&#xff1a; 瞧&#xff01;连易拉罐的拉环也化身成…

【GPT调用】本地使用python调用GPT接口

python调用GPT接口 环境变量设置主调用方法执行结果 环境变量设置 .env文件中配置GPT环境变量 api_key"你的GPT-API-KEY" urlhttps://ai-proxy.ksord.com/wps.openai.azure.com/openai/deployments/gpt-4-32k/chat/completions?api-version2023-09-01-preview主调…

Oracle SQL Developer导出数据库表结构,表数据,索引以及序列号等对象

通过Oracle SQL Developer软件将指定oralce数据库中的表结构&#xff0c;表数据&#xff0c;索引以及序列号等对象导出成SQL文件。 数据库版本&#xff1a;Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production 软件版本&#xff1a;Oracle SQL Develo…

【千帆平台】使用AppBuilder零代码创建应用,Excel表格数据转为Markdown格式文本

欢迎来到《小5讲堂》 这是《千帆平台》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言创建应用应用名称应用描述应用头像角色指令组件能力开场白推…