你真的了解Redis的list数据结构吗--redis之面试官爱我系列(2)

List(列表)

各位好我是霜华,今天将一个在开发中很常用的一个数据结构(用于消息队列)
下面开讲!!!
在这里插入图片描述
基本定义:
有序可重复,类似LinkedList ,插⼊和删除块,复杂度O(1),索引定位很慢复杂度O(n)
是⼀个字符链表,内部结构类linkedList (双向链表),left,right 都可以插⼊添加,如果健不存
在,创建新的链表,如果健已存在,新增内容,
如果值全部移除,对应的健也就消失了(⼈话:容器没东⻄了,容器就销毁)
列表最多可存储2^32-1 元素(4294967295 每个类表可存储40多亿)
原理:
底层是⼀个“快速链表”(quicklist)的结构,在列表元素较少时,使⽤连续的内存存储成压缩列表
ziplist。当数据量较多时,改成quicklist,也是讲多个ziplist使⽤双向指针串起来使⽤,以减少内存的
碎⽚化。

详细原理:

list有两种形态:

ziplist(连续内存) 和 quicklist(链表和ziplist结合,一定程度提高了改的性能,也减少了空间占用问题,小孩子才做选择,性能和空间我都要)

list的结构和LinkList很像但它不是一味的照搬,因为LinkList确实增删改很快,但因为他一个元素有前元素地址、自己元素、后元素地址这导致

1、因为你需要一遍遍访问地址,它遍历实在是太慢了

2、我存一个元素实在太花空间了

这时候ziplist这种包裹状的数据结构在数据不是很多时候,很吃香。(为什么:跟我想,你把所有数据放进一个包里,他们地址都是连续的,你可以顺着那条线一个个找,少的时候还好说,数据多的时候呢,你怎么找)


zipList压缩列表:

在容器对象的元素葛素会用压缩列表进行存储,一个ziplist的底层是一块连续的内存空间没有任何空余(就是没有元素之外的信息(LinkLIst单位信息大)。或者空余(String 有空余空间))

压缩包压缩包之间就是靠着互有地址相互链接

在这里插入图片描述
ziplist 内部代码和示意图

struct ziplist<T>{
    int32 zlbytes;
    int32 zltail_offset;
    int16 zllength;
    T[]entries;
    int8 zlend;
}

zltbyes://表示整个压缩列表的占用字节数

zltail_offset://压缩包最后一个元素距离压缩列表起始位置的偏移量,(包与包之间是双向链表,查找某个元素就不用遍历拉,快速定位定位到这个最后一个元素)(@linklist 学学人家学学!!!)

zllength:/元素个数

entries//元素内容列表,一次紧凑存储

zlend//标志压缩列表的结束,值恒为0xFF
在这里插入图片描述

单个entry的结构

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

prevlen //上一个entry 的字节长度,当倒着遍历时,可以之间定位到下个元素的位置,相当于有了它你就可以跳过去了,而不是顺着那根线找

当字符串长度小于254,prevlen用一个字节表示,超出254时候,用5个字节表示

encoding字段存储了元素内容的编码类型信息,ziplist通过这个来决定后面的content形式

redis如何根据encoding前缀为来区分内容

在这里插入图片描述
在这里插入图片描述
ziplist如何增加元素:

因为其紧凑存储,无冗余空间,每加入新元素就要扩容

可能会重新分布内存空间,将原来的数据copy过去,如果数据很大,增加元素会有很大内存消耗


quicklist:

以前redis的list 在元素多时候 用linklist存储,但链表附加空间太高了,两个指针占了16字节,而且元素之间在内存都是零散分布,之后quiccklist替代(ziplist,和linklist混合)

它将linkedlist 按段分,为异端用ziplist压缩,多一个ziplist之间用双向指针串起来

在这里插入图片描述

实现原码:

struct quicklistNode{
    quicklistNode prev;
    quicklistNode next;
    ziplist* zl;//指向压缩列表
    int32 size;//指向的字节总数
    int16 count;//元素数量
    int2 encoding;//存储
}
strcut quicklist{
    quicklistNode head;
    quicklistNode tail;
    long count;//元素总数
    int nodes;//ziplist节点个数
    int compressDepth //LZF算法压缩深度
}

Redis可能会对ziplist进行又一次压缩(我真的一滴也不剩了)

叫压缩深度:

默认是0,不压缩

1:quicklist首位不压缩

2:quicklist首位第一个和第二个不压缩

(quicklist中的ziplist默认其长度位8kb)


*命令:

a、队列操作:

rpush: rpush list2 1 2 3 4 5(从右边存⼊数据)

lrange:遍历:lrange list2 0 -1(得到对应范围内的值,如上⾏得12345)(慢加载)

llen:查长:lien list2 (查看长度)

lpop:删:lpop list2(从左侧弹出,返回弹出的数据5)

b、栈操作:

rpush: rpush list2 1 2 3 4 5

rpop:删除) list2(从右侧弹出5)

lpush list 1 2 3 4 5 (从左边存⼊数据)(栈结构)

c、遍历操作:(不建议调用这个实在实在太慢了)

1、lindex :定点查:lindex liset2 n 获取某个位置的值,小角标从0开始(时间复杂度为0(n))

2、lren:看数删:lren list2 n m 从左边开始,如果值等于m就删除,直到删除数量到n

3、lset+index:set list n m 吧第n位变成m(更改指定位置的值)(n从0开始算起)//像集合的set方法

4、linsert+before/after:linsert list after n m 在n这个数的后⾯插⼊m、linsert list before n m 在n这个数的前⾯插⼊m。

5、ltrm :截取:ltrim list2 n m 从n到m截取出来,其他东⻄不要了

(注:很多内容皆来自 《Redis深度历险 核心原理与应用实践》这本书)

至于与它相关的消息队列我会抽一期来单独讲,今天先到着我们下期见!在这里插入图片描述

原创文章 6 获赞 0 访问量 571

猜你喜欢

转载自blog.csdn.net/weixin_45898658/article/details/106040165
今日推荐