搜索
您的当前位置:首页正文

Redis底层实现---Ziplist

来源:好走旅游网

Redis底层实现—Ziplist

简介

redis 是开源用C语言编写的一个远程的KV词典存储服务,里面有很多经典的设计结构对后续的设计很有启发, 其中最著名的恐怕就是排序链表的底层实现—跳表。
本次要说的是他的另外一个核心的实现,他的重要程度应该说一定程度上来说远高于跳表,他的名字就是压缩链表。

底层数据结构

Redis 有 5 种基础数据结构,分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合) , 而这5种常见数据结构底层实现分别为:

  • string 采用SDS 或者INT 来存放
  • list 采用ziplist 或者双端链表来实现(单个元素小于64字节,总个数小于512使用ziplist)。
  • set 使用 intset 和 hashtable 两种实现。
  • hash 的编码是 ziplist 或者 hashtable。
  • zset 即是有序集合,的编码是ziplist 或者 skip-list (单个元素小于64字节,128个元素一下 用ziplist)

为啥说它

redis 底层设计结构有很多,为啥要偏偏说“它”呢?

从中不难发现,ziplist 在常见五种数据结构的底层实现中,其中有3种的底层实现都跟他相关,所以我们能看出这个设计应用有多广 而且不难发现三个特点:

  • 都是有序&集合类型数据结构的底层实现
  • 都是要求单个元素较&总元素较情况
  • 在元素个数较多的时候都有其他的代替实现

既然这些集合都有自己标准的实现,为啥非要在元素小的时候使用ziplist 作为它们的底层实现呢?

####备注:对原理不感兴趣的同学可以直接跳过原理,看最后的结论部分

原理

ziplist是由一系列特殊编码的连续内存块组成的顺序存储结构,类似于数组,ziplist在内存中是连续存储的,但是不同于数组,为了节省内存 ziplist的每个元素所占的内存大小可以不同,每个节点可以用来存储一个整数或者一个字符串。

  • zlbytes:4个字节。记录压缩列表总共占用的字节数,在对压缩列表进行内存重分配时使用
  • zltail:4个字节。可通过这个字段快速定位到链表末尾 zllen:2个字节。记录总共有多少个entry
  • entry:具体数据的内容就存在这里 zlend:1个字节。为十六进制值0xFF,标记一个压缩列表的末尾

其中每个entry 都是一个动态结构,并非固定结构因此也可以存放hash类型结构。

从上图中可以看出, 其实属于一种动态数组的变种,在原有基础上增加了 尾节点位置,也是为了方便查看。

ziplist的整体设计中类似于SDS一样, 与标准的c++ STL 的vector相比申请内存没有预分配的多余空间的操作(当前本身目的就是为了节约内存,所以更不可能申请多余的内存空间)

基于ziplist 操作的时候, 读取头尾节点虽然都是O(1) 的时间复杂度。但是插入和删除都需要进行内存拷贝,复杂度为O(n), ziplist 插入和删除的最坏情况下极低概率会引起连锁反应插入复杂度为O(n2)。
这种实现比起linkedlist O(1) 的插入复杂度 肯定是比不了的,因此在元素个数比较多的时候肯定不会选用ziplist 这种实现,时间耗费太大,但是对于个数比较少的情况,由于连续内存没有指针节点浪费,节约比例比较高,所以会选用这种实现。

通过ziplist 设计其实我们依然可以发现,任何设计只有合适不合适,没有完全意义下的好与坏

结论

为了节约内存而设计的:

  • ziplist 结构主要是目标是为了解决内存浪费的情况,可以将内存充分紧凑使用,节约内存空间。
  • 但也由于是使用的连续内存,不适合存储存储太大或者元素个数太多,这样会导致申请的内存块太大,使用起来不灵活。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top