Redis 中的 list 是类似于双端队列的一种实现,其底层的数据结构涉及到 linkedlist、ziplist、quicklist 和 listpack 的演进
redis 中的 linkedlist 是双链表,这也是我们实现 list 时首先想到的数据结构之一。redis 中的双链表并没有非常特殊的地方,我们来简单看下对应的代码实现即可
typedef struct list {
listNode *head;//头指针
listNode *tail;//尾指针
void *(*dup)(void *ptr);//节点复制函数
void (*free)(void *ptr);//节点释放函数
int (*match)(void *ptr, void *key);//节点值是否相等
unsigned long len;//链表节点数量
} list;
typedef struct listNode {
struct listNode *prev;//前驱节点
struct listNode *next;//后继节点
void *value;//值
} listNode;
我们可以发现,双链表是一种非常标准的结构,链表维护首尾节点指针,维护长度,还和维护必要的工具函数指针地址,链表节点维护前驱、后继节点以及对应的值,正常来讲这套结构没有问题,但挑剔一点的话,它会有两个问题:
为了解决张两点,Redis 创造了 ziplist
针对我们上面提到的两个问题,对应的解决思路就是结构简单+内存连续,而 ziplist 正是这样一种结构。
ziplist 首先是一块连续的内存,然后按一定的规范维护了简单的节点结构,如下图所示
ziplist 各组成部分功能为:
我们看到 ziplist 节点没有维护首尾指针,又针对不同情况实现各种变长存储,为了应对变长存储下的变量,维护了一个 prelen 字段,可以理解为用时间换了部分空间,在数据量小的情况下会有不错表现,但是它有个注明的缺点:连锁更新
我们现在知道,对于节点序列 ABC,节点 A 的长度可能会影响到节点 B 的 prelen 的长度,而节点 B 的 prelen 字段长度变更会导致节点 B 整体长度变更,这就有可能触发节点 C 遇到类似的情况,所以在极端场景下,一个节点数据的变更可能会引发后续节点的连锁反应,这就是 ziplist 的连锁更新。
为了解决连锁更新的问题,redis 又造了一个新的结构:quicklist
todo
todo
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。