为了加快速度,Redis都做了哪些“变态

本文介绍了Redis3.2版本之前和之后列表存储结构的变化,从linkedlist和ziplist的选择,到quicklist的出现,着重讲解了quicklist的数据结构、压缩机制以及与原始编码的改进。
摘要由CSDN通过智能技术生成

linkedlist 和 ziplist 的选择


Redis3.2 之前,linkedlistziplist 两种编码可以进选择切换,如果需要列表使用 ziplist 编码进行存储,则必须满足以下两个条件:

  • 列表对象保存的所有字符串元素的长度都小于 64 字节。

  • 列表对象保存的元素数量小于 512 个。

一旦不满足这两个条件的任意一个,则会使用 linkedlist 编码进行存储。

PS:这两个条件可以通过参数 list-max-ziplist-valuelist-max-ziplist-entries 进行修改。

这两种列表能在特定的场景下发挥各自的作用,应该来说已经能满足大部分需求了,然后 Redis 并不满足于此,于是一场改革引发了,quicklist 横空出世。

quicklist


Redis 3.2 版本之后,为了进一步提升 Redis 的性能,列表对象统一采用 quicklist 来存储列表对象。quicklist存储了一个双向列表,每个列表的节点是一个 ziplist,所以实际上 quicklist 并不是一个新的数据结构,它就是linkedlistziplist 的结合,然后被命名为快速列表。

quicklist 内部存储结构

quicklist 中每一个节点都是一个 quicklistNode 对象,其数据结构定义如下:

typedef struct quicklistNode {

struct quicklistNode *prev;//前一个节点

struct quicklistNode *next;//后一个节点

unsigned char *zl;//当前指向的ziplist或者quicklistLZF

unsigned int sz;//当前ziplist占用字节

unsigned int count : 16;//ziplist中存储的元素个数,16字节(最大65535个)

unsigned int encoding : 2; //是否采用了LZF压缩算法压缩节点 1:RAW 2:LZF

unsigned int container : 2; //存储结构,NONE=1, ZIPLIST=2

unsigned int recompress : 1; //当前ziplist是否需要再次压缩(如果前面被解压过则为true,表示需要再次被压缩)

unsigned int attempted_compress : 1;//测试用

unsigned int extra : 10; //后期留用

} quicklistNode;

然后各个 quicklistNode 就构成了一个快速列表 quicklist

typedef struct quicklist {

quicklistNode *head;//列表头节点

quicklistNode *tail;//列表尾节点

unsigned long count;//ziplist中一共存储了多少元素,即:每一个quicklistNode内的count相加

unsigned long len; //双向链表的长度,即quicklistNode的数量

int fill : 16;//填充因子

unsigned int compress : 16;//压缩深度 0-不压缩

} quicklist;

根据这两个结构,我们可以得到 Redis 3.2 版本之后的列表对象的一个存储结构示意图:

在这里插入图片描述

quicklist 的 compress 属性

compress 是用来表示压缩深度,ziplist 除了内存空间是连续之外,还可以采用特定的 LZF 压缩算法来将节点进行压缩存储,从而更进一步的节省空间,压缩深度可以通过参数 list-compress-depth 控制:

  • 0:不压缩(默认值)

  • 1:首尾第1个元素不压缩

  • 2:首位前2个元素不压缩

  • 3:首尾前3个元素不压缩

  • 以此类推

注意:之所以采取这种压缩两端节点的方式是因为很多场景都是两端的元素访问率最高的,而中间元素访问率相对较低,所以在实际使用时,我们可以根据自己的实际情况选择是否进行压缩,以及具体的压缩深度。

quicklistNode 的 zl 指针

zl 指针默认指向了 ziplist,上面提到 quicklistNode 中有一个 sz 属性记录了当前 ziplist 占用的字节,不过这仅仅限于当前节点没有被压缩(通过LZF 压缩算法)的情况,如果当前节点被压缩了,那么被压缩节点的 zl 指针会指向另一个对象 quicklistLZF,而不会直接指向 ziplistquicklistLZF 是一个 4+N 字节的结构:

typedef struct quicklistLZF {

unsigned int sz;// LZF大小,占用4字节

char compressed[];//被压缩的内容,占用N字节

} quicklistLZF;

quicklist 对比原始两种编码的改进

quicklist 同样采用了 linkedlist 的双端列表特性,然后 quicklist 中的每个节点又是一个 ziplist,所以quicklist 就是综合平衡考虑了 linkedlist 容易产生空间碎片的问题和 ziplist 的读写性能两个维度而设计出来的一种数据结构。使用 quicklist 需要注意以下 2 点:

  • 如果 ziplist 中的 entry 个数过少,最极端情况就是只有 1entry 的压缩列表,那么此时 quicklist 就相当于退化成了一个普通的 linkedlist

  • 如果 ziplist 中的 entry 过多,那么也会导致一次性需要申请的内存空间过大(ziplist 空间是连续的),而且因为 ziplist 本身的就是以时间换空间,所以会过多 entry 也会影响到列表对象的读写性能。

ziplist 中的 entry 个数可以通过参数 list-max-ziplist-size 来控制:

list-max-ziplist-size 1

注意:这个参数可以配置正数也可以配置负数。正数表示限制每个节点中的 entry 数量,如果是负数则只能为 -1~-5,其代表的含义如下:

  • -1:每个 ziplist 最多只能为 4KB

  • -2:每个 ziplist 最多只能为 8KB

  • -3:每个 ziplist 最多只能为 16KB

  • -4:每个 ziplist 最多只能为 32KB

  • -5:每个 ziplist 最多只能为 64KB

列表对象常用操作命令


自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

百度、字节、美团等大厂常见面试题

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
.(img-SvASCdoR-1712271511113)]

[外链图片转存中…(img-lISx3Vy2-1712271511113)]

百度、字节、美团等大厂常见面试题

[外链图片转存中…(img-WdUB1vlJ-1712271511113)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值