[Redis]基础数据结构(二)list 列表

目录

前言:

1. 简单概括list

1.1 队列

1.2 栈

1.3 快速链表(底层存储)

2. 源码解读

2.1 压缩列表的结构

2.2 intset小整数集合

2.3 quicklist


前言:

继续上一篇:[redis]基础数据结构(一)String 

https://blog.csdn.net/pmdream/article/details/104871358

内容为《Redis深度历险:核心原理与应用实践》的笔记

1. 简单概括list

相当于Java里面的LinkedList。但是他是链表而不是数组。(String 更像是数组类型)

这意味着list的插入和删除操作都特别快,时间复杂度位O(1)

但是查找会特别慢,时间复杂度位O(n).

列表中的每个元素都是用双向指针顺序。(支持向前和向后遍历)

1.1 队列

队列是一种右边进左边出的,先进先出的数据结构。

常用:消息排队和异步逻辑处理,确保元素的访问的顺序性。

我之前做的一个项目就是,要进行排队机制,一个公司的客服先进先出。

这样进行排队。

rpush  and  lpop

1.2 栈

这种场景很不常见,是一种先进后出。

1.3 快速链表(底层存储)

redis的底层存储并不是一个简单的linkedlist 而是一种称作为快速链表的一种结构。

在列表元素比较少的时候,会使用一块连续的内存存储,这种结构就是ziplist

所有元素挨在一起存储,但是如果数据很大的时候就回试用quicklist。

因为普通的链表需要的附加指针空间数据会浪费空间,而且会导致内存的碎片化

比如普通链表存放的只是int类型的数据,结构还需要prev和next的指针,所以很浪费空间。

ziplist压缩链表就不会,所以redis将链表和ziplist结合起来组成了快速列表。

多个ziplist使用双向指针就形成了redis 的快速列表。

2. 源码解读

2.1 压缩列表的结构

struct ziplist<T> {

int32 zlbytes; //整个压缩列表占用的字节数

int32 zltail_offset; //最后一个元素距离压缩列表起始位置的偏移量,用于快速的定位到最后一个结点

int16 zllength; //元素个数

T[] entries; //元素内容列表,紧凑结构

int8 zlend; //标志压缩列表的结束,值恒定为0xFF

}

zltail_offset 这个值就是为了支持双向遍历所以才会有的,能够快速的到最后一个元素,然后倒着遍历。

对于zip存的entry,里面是有与之前元素的距离信息的,所以才能找到前面元素位置。

entry:

struct entry {
     int<var> prevlen; // 前一个 entry 的字节长度

     int<var> encoding; // 元素类型编码
     optional byte[] content; // 元素内容

}

这边的prevlen是一个变长的整数。

redis中为了节省存储空间,对encoding的字段有着复杂的设计。通过这个可以识别具体存储的数据形式。

压缩列表通常是存储小数据的。原因跟下面增加元素也有关。

压缩列表增加元素:

因为紧凑的存储,没有冗余,所以插入一个元素就需要调用realloc拓展空间。

具体可能看原有空间还能不能接上,如果有的话,那么在原有拓展。

如果没有的话申请新的内存空间,然后把老的拷贝过去。

2.2 intset小整数集合

这个与标题list无关,但是其实zset和hash容器在元素个数很少的时候,也会采用亚索列表的形式进行存储。

对于set都存放整数而且数量很少的时候,那么会使用intset

但是比如都是整数的时候,放了一个非整数的,存储形式就会从intset变成了hash结构

2.3 quicklist

redis以前也是ziplist + linkedlist(元素很多的时候)

为什么改了,因为链表的附加空间太高了。

吹爆redis啊,真的nb。

为了进一步节省空间的话,Redis还会对ziplist进行压缩,使用LZF压缩算法(这个也不是很懂,书上也没怎么说)

struct ziplist { ...
}
struct ziplist_compressed {
    int32 size;
    byte[] compressed_data;
}
struct quicklistNode {
    quicklistNode* prev;
    quicklistNode* next;
    ziplist* zl; // 指向压缩列表
    int32 size; // ziplist 的字节总数
    int16 count; // ziplist 中的元素数量
    int2 encoding; // 存储形式 2bit,原生字节数组还是 LZF 压缩存储 ...
}
struct quicklist {
    quicklistNode* head;
    quicklistNode* tail;
    long count; // 元素总数
    int nodes; // ziplist 节点的个数
    int compressDepth; // LZF 算法压缩深度 ...
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值