深入理解Redis 底层数据结构之QuickList 与ZipList
centos7安装redis6.25结合docker镜像配置方法(附redis.conf文件)
list底层的数据结构:
-
linkedList 链表
-
zipList 压缩列表
-
quickList 快链表
在3,2版本之前,列表是通过双向链表或压缩链表来实现的。他们之间可以互相转换,在3.2版本之后又新加入了新的数据结构:QuickList,也就是双向链表和压缩列表的结合。
链表:LinkedList
-
数据结构中常用的带头节点的双向链表,并且带有指向头节点的头指针和指向最后一个节点的尾指针,双向链表保证从任意一个位置可以向前或者向后进行遍历,但要注意头节点的前指针为null,尾节点的后指针为空,这也就说明了redis中的LinkedList数据结构是一个无环链表,不支持逆序遍历
-
第二点就是说,操作命令中的
lpush(left push) 、lpop(left pop )等命令中的left代表从队头进行操作,right代表从队尾进行操作。 -
结构中的
len字段记录了整个链表的长度。 -
由于链表本身的特性,对链表进行增删操作所需的时间非常少,时间复杂度仅为O(1);但如果是需要凭借索引寻找链表中某个值,时间花销就显得有些高,时间复杂度为O(n)
-
dup函数用于对某个链节点进行复制操作 -
free函数用于对某个链节点进行释放操作,也就是删除 -
match函数用于判断某个链节点的值和输入的值是否相等。
压缩列表:ZipList
- redis中的压缩列表是用字节数组作为其数据结构。
- 在zipList的数据结构中有以下字段:
zlbytes:整个压缩列表所占用的字节数,本身是4个字节即32位,因此压缩链表的最大长度为(2^32-1)个字节zltail_offset:压缩列表尾部的元素到起始地址的偏移量,可以直接找到表尾元素,即支持逆序遍历zlength:表中元素的个数,占2字节,如果列表中的元素个数超过(2^16-1)个,那么需要遍历整个列表才能得到元素的个数entry:列表中存储的元素,可能是整数,也可能是字节数组,具体结果见下图zlend:元素的结束标志,占一个字节,是一个常量OXFF
-
entry保存中列表中的元素,可能是整数,也可能是字节数组。其结构体有三个字段:
-
pre_length:上一个元素的长度,方便逆序遍历的时候直接找到上个节点的起始位置。当前一个元素的长度小于254个字节的时候,用一个字节表示;当前一个元素的长度大于等于254个字节的时候,用5个字节表示,此时前一个字节存储固定值254。 -
encoding: 长度为两个 bit 。 它的值可以是 00 、 01 、 10 和 11 。00 、 01 和 10表示 content 部分保存着字符数组,11表示 content 部分保存着整数。 -
content:保存真正的元素。
-
转换条件:
创建一个列表是,默认使用的数据结构是zipList,但在满足以下条件的时候,zipList会自动转化为双向链表:
- 压缩列表中插入了一个过长的字符串(长度可配置,默认65)
- 压缩列表中的节点数超过某一数量(默认512)
总结
-
当存储的元素很少的时候,通常采用zipList作为基础数据结构,而当数据元素较多时则采用LinkedList。
-
从数据结构本身的特点而言:LinkedList在插入和删除元素方面具有很大的优势。但其需要额外存储两个指针,存储开销比较大,而且每个元素都是单独的内存空间,地址不连续,容易造成内存碎片。
-
而压缩列表存储在一块连续的内存空间中,但是增加删除元素开销较大,在内存扩容执行realloc操作的时候需要进行大量的拷贝操作
快速列表:QuickList
redis3.2之后,增加了新的数据结构:QuickList。它结合了LinkedList和zipList的优点。它将LinkedList的每个节点都用zipList的方式来存储。LinkedList节点之间依然采用双向链表连接起来,只

本文深入探讨Redis中的三种列表数据结构:链表(LinkedList)、压缩列表(ZipList)和快速列表(QuickList)。分析了每种数据结构的特点、应用场景以及转换条件,并提供了实际操作示例。
最低0.47元/天 解锁文章
1108





