redis 是开源用C语言编写的一个远程的KV词典存储服务,里面有很多经典的设计结构对后续的设计很有启发, 其中最著名的恐怕就是排序链表的底层实现—跳表。
本次要说的是他的另外一个核心的实现,他的重要程度应该说一定程度上来说远高于跳表,他的名字就是压缩链表。
Redis 有 5 种基础数据结构,分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合) , 而这5种常见数据结构底层实现分别为:
redis 底层设计结构有很多,为啥要偏偏说“它”呢?
从中不难发现,ziplist 在常见五种数据结构的底层实现中,其中有3种的底层实现都跟他相关,所以我们能看出这个设计应用有多广 而且不难发现三个特点:
既然这些集合都有自己标准的实现,为啥非要在元素小的时候使用ziplist 作为它们的底层实现呢?
####备注:对原理不感兴趣的同学可以直接跳过原理,看最后的结论部分
ziplist是由一系列特殊编码的连续内存块组成的顺序存储结构,类似于数组,ziplist在内存中是连续存储的,但是不同于数组,为了节省内存 ziplist的每个元素所占的内存大小可以不同,每个节点可以用来存储一个整数或者一个字符串。
其中每个entry 都是一个动态结构,并非固定结构因此也可以存放hash类型结构。
从上图中可以看出, 其实属于一种动态数组的变种,在原有基础上增加了 尾节点位置,也是为了方便查看。
ziplist的整体设计中类似于SDS一样, 与标准的c++ STL 的vector相比申请内存没有预分配的多余空间的操作(当前本身目的就是为了节约内存,所以更不可能申请多余的内存空间)
基于ziplist 操作的时候, 读取头尾节点虽然都是O(1) 的时间复杂度。但是插入和删除都需要进行内存拷贝,复杂度为O(n), ziplist 插入和删除的最坏情况下极低概率会引起连锁反应插入复杂度为O(n2)。
这种实现比起linkedlist O(1) 的插入复杂度 肯定是比不了的,因此在元素个数比较多的时候肯定不会选用ziplist 这种实现,时间耗费太大,但是对于个数比较少的情况,由于连续内存没有指针节点浪费,节约比例比较高,所以会选用这种实现。
通过ziplist 设计其实我们依然可以发现,任何设计只有合适不合适,没有完全意义下的好与坏
为了节约内存而设计的:
因篇幅问题不能全部显示,请点此查看更多更全内容