Redis中的List也是一种非常常用的存储结构,它和Java中的List结构类似,通常用来存储一个列表或者作为队列实现,在Redis3.2之前,list采用了两种数据结构作为底层实现:压缩列表ziplist以及双向链表adlist,在3.2之后,使用quicklist替代,本篇文章将带你了解Redis底层的三种存储结构。
双向链表adlistC语言没有内置这种数据结构的实现,Redis构建了自己的链表结构,一个元素结构如下:(点我查看源码地址)
/*Node,List,andIteratoraretheonlydatastructuresusedcurrently.*/typedefstructlistNode{structlistNode*prev;//上一元素structlistNode*next;//下一元素void*value;//元素值}listNode;
多个listNode组成了一个双向链表结构,以及提供了相关的链表操作的函数,如下:
typedefstructlist{//头结点listNode*head;//尾元素listNode*tail;//元素值复制函数void*(*dup)(void*ptr);//元素值释放函数void(*free)(void*ptr);//元素值对比函数int(*match)(void*ptr,void*key);//元素长度unsignedlonglen;}list;
图例:Redis的链表是一个双端链表结构,它有如下特点:
无环的结构(尾的next没有指向头,头的prev没有指向尾)在list中维护了len很方便的可以取到链表的长度,复杂度是o(1)使用void*指针保存元素的值可以保存各种类型的值对链表的表头和表尾进行插入的复杂度都为o(1)但是链表的缺点也是比较明显的,就是链表的附加空间比较高,在数据较小的时候会造成空间的浪费,prev和next就需要占用16个字节(64bit的系统,指针8字节),每个元素的内存是独立分配的,不要求连续性,会增加内存的碎片化,影响内存管理效率。所以它不适合存储少量或者小数据。所以Redis在列表对象中小数据量的时候使用压缩列表ziplist作为底层实现。
压缩列表ziplistziplist本质上就是一个字节数组,是Redis为了解决内存而设计的一种线性数据结构,Redis中的有序集合,散列,列表都直接或者间接使用到了压缩列表。在Redis源码中有这么一段注释对ziplist做了解释:ziplist源码
Theziplistisaspeciallyencodedduallylinkedlistthatisdesignedtobeverymemoryefficient.Itstoresbothstringsandintegervalues,whereintegersareencodedasactualintegersinsteadofaseriesofcharacters.ItallowspushandpopoperationsoneithersideofthelistinO(1)time.However,becauseeveryoperationrequiresareallocationofthememoryusedbytheziplist,theactual