ZipList - 压缩列表

ziplist 是为了提高存储效率而设计的一种特殊编码的双向链表。它可以存储字符串或者整数,存储整数时是采用整数的二进制而不是字符串形式存储。它能在O(1)的时间复杂度下完成list两端的push和pop操作。但因为每次操作都需要重新分配内存,所以实际复杂度和ziplist的内存使用量相关。

ziplist 结构

<zlbytes><zltail><zllen><entry>...<entry><zlend>

  • zlbytes 字段的类型是unit32_t, 这个字段存储的是整个ziplist所占用的内存的字节数
  • zltail 字段的类型是unit32_t, 它指的是ziplist 中最后一个entry 的偏移量
  • zllen 字段的类型是unit16_6,entry的数量。2bytes,如果数量小于65535,它就是实际值,如果大于,则需要逐个遍历entry才能得到实际数值
  • zlend 终止字节

Entry 结构

<prevlen><encoding><entry-data> 或者 <prevlen><encoding><entry-data>

  • prevlen 前一个entry 的大小
  • encoding 不同的情况下值不同,用于表示当前entry 的类型和长度
  • entry-data 真实用于存储entry表示的数据
  • entry 中存储的是int类型时,encoding 和 entry-data 会合并在encoding 中表示,此时没有entry-data字段
prevlen 编码

当前一个元素长度小于254的时候,prevlen 长度为1个字节,值即为前一个entry的长度,如果长度大于等于254的时候,prevlen 用5个字节表示,第一个字节设置为254,后面四个字节存前一个entry的长度

encoding 编码

encoding 的长度和值根据保存的是int还是string,还有数据的长度而定;
前两位用来表示类型,当为 11 时,表示存储的是int, 其他表示存储的是string

存储 string 时:
  • |00pppppp|:后六位表示string长度,entry-data 长度不能超过63;
  • |01pppppp||qqqqqqqq|:后14位表示string长度,entry-data 长度不能超过16383;
  • |10000000|qqqqqqqq|rrrrrrrr|ssssssss|ttttttt| 此时encoding长度为5个字节,后面的4个字节用来表示encoding中存储的字符串长度,长度不能超过2^32 - 1;
存储int 时:
  • |11000000| encoding 为3个字节,后2个字节表示一个int16;
  • |11010000| encoding为5个字节,后4个字节表示一个int32;
  • |11100000| encoding 为9个字节,后8字节表示一个int64;
  • |11110000| encoding为4个字节,后3个字节表示一个有符号整型;
  • |11111110| encoding为2字节,后1个字节表示一个有符号整型;
  • |1111xxxx| encoding长度就只有1个字节,xxxx表示一个0 - 12的整数值;
为什么 ziplist 特别省内存
  • 普通数组每个元素占用的内存是一样的且取决于最大的那个元素
  • ziplist 为了让每个元素按照实际的内容大小存储,所以增加 encoding 字段,针对不同的encoding 来袭话存储大小
  • prevlen 是为了从后向前操作节点
缺点
  • 不预留空间,并且在移除节点后,立即缩容,代表每次写操作都会进行内存分配操作
  • 节点扩容:最坏情况下,第一个节点的扩容,会导致整个ziplist表中的后续所有节点的entry.prevlen字段扩容

posted on 2022-11-21 22:29  每日问答  阅读(124)  评论(0)    收藏  举报

导航