https://juejin.cn/post/6914456200650162189

前言

简介

官方文档中关于 ziplist 的介绍如下:

/* The ziplist is a specially encoded dually linked list that is designed
 * to be very memory efficient. It stores both strings and integer values,
 * where integers are encoded as actual integers instead of a series of
 * characters. It allows push and pop operations on either side of the list
 * in O(1) time. However, because every operation requires a reallocation of
 * the memory used by the ziplist, the actual complexity is related to the
 * amount of memory used by the ziplist.
 */

翻译过来是:ziplist 是一个经过特殊编码的双向链表,它的设计目标是节约内存。它可以存储字符串或者整数。其中整数是按二进制进行编码的,而不是字符串序列。它能以 O(1) 的时间复杂度在列表的两端进行 push 和 pop 操作。但是由于每个操作都需要对 ziplist 所使用的内存进行重新分配,所以实际操作的复杂度与 ziplist 占用内存大小有关。

文档中描述 ziplist 是一个 dually linked list,这句话其实不太容易理解。

因为 ziplist 的设计目标是为了 节约内存,而链表的各项之间需要使用指针连接起来,这种方式会带来大量的内存碎片,而且地址指针也会占用额外的内存,这与 ziplist 的设计初衷不符。而且后面我们看了 ziplist 的数据结构就会发现,ziplist 实际上是一块连续的内存。

因此我们可以这么理解:ziplist 是一个特殊的双向链表,特殊之处在于:没有维护双向指针,prev、next,而是存储了上一个 entry 的长度和当前 entry 的长度,通过长度推算下一个元素。

总结一下:

用途

Redis 的 有序集合散列列表 都直接或者间接使用了压缩列表。当有序集合或散列表的元素个数比较少,且元素都是短字符串时,Redis 便使用压缩列表作为其底层数据存储。列表使用快速链表(quicklist)数据结构存储,而快速链表就是双向链表与压缩列表的组合。

比如我们使用下面命令创建个 hash 表,并查看其编码

127.0.0.1:6379> hmset person name wys gender 1 age 24
OK
127.0.0.1:6379> object encoding person
"ziplist"

可以看到,当 hash 表元素个数较少且都是短字符串时,其数据类型确实是 ziplist。