Redis 列表对象
列表对象的编码可以是 ziplist
或者 linkedlist
。
ziplist
编码的列表对象使用压缩列表作为底层实现, 每个压缩列表节点(entry)保存了一个列表元素。
举个例子, 如果我们执行以下 RPUSH 命令, 那么服务器将创建一个列表对象作为 numbers
键的值:
redis> RPUSH numbers 1 "three" 5 (integer) 3
如果 numbers
键的值对象使用的是 ziplist
编码, 这个这个值对象将会是图 8-5 所展示的样子。
另一方面, linkedlist
编码的列表对象使用双端链表作为底层实现, 每个双端链表节点(node)都保存了一个字符串对象, 而每个字符串对象都保存了一个列表元素。
举个例子, 如果前面所说的 numbers
键创建的列表对象使用的不是 ziplist
编码, 而是 linkedlist
编码, 那么 numbers
键的值对象将是图 8-6 所示的样子。
注意, linkedlist
编码的列表对象在底层的双端链表结构中包含了多个字符串对象, 这种嵌套字符串对象的行为在稍后介绍的哈希对象、集合对象和有序集合对象中都会出现, 字符串对象是 Redis 五种类型的对象中唯一一种会被其他四种类型对象嵌套的对象。
注意
为了简化字符串对象的表示, 我们在图 8-6 使用了一个带有 StringObject
字样的格子来表示一个字符串对象, 而 StringObject
字样下面的是字符串对象所保存的值。
比如说, 图 8-7 代表的就是一个包含了字符串值 "three"
的字符串对象, 它是 8-8 的简化表示。
编码转换
当列表对象可以同时满足以下两个条件时, 列表对象使用 ziplist
编码:
- 列表对象保存的所有字符串元素的长度都小于
64
字节; - 列表对象保存的元素数量小于
512
个;
不能满足这两个条件的列表对象需要使用 linkedlist
编码。
注意
以上两个条件的上限值是可以修改的, 具体请看配置文件中关于 list-max-ziplist-value
选项和 list-max-ziplist-entries
选项的说明。
对于使用 ziplist
编码的列表对象来说, 当使用 ziplist
编码所需的两个条件的任意一个不能被满足时, 对象的编码转换操作就会被执行: 原本保存在压缩列表里的所有列表元素都会被转移并保存到双端链表里面, 对象的编码也会从 ziplist
变为 linkedlist
。
以下代码展示了列表对象因为保存了长度太大的元素而进行编码转换的情况:
# 所有元素的长度都小于 64 字节 redis> RPUSH blah "hello" "world" "again" (integer) 3 redis> OBJECT ENCODING blah "ziplist" # 将一个 65 字节长的元素推入列表对象中 redis> RPUSH blah "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww" (integer) 4 # 编码已改变 redis> OBJECT ENCODING blah "linkedlist"
除此之外, 以下代码展示了列表对象因为保存的元素数量过多而进行编码转换的情况:
# 列表对象包含 512 个元素 redis> EVAL "for i=1,512 do redis.call('RPUSH', KEYS[1], i) end" 1 "integers" (nil) redis> LLEN integers (integer) 512 redis> OBJECT ENCODING integers "ziplist" # 再向列表对象推入一个新元素,使得对象保存的元素数量达到 513 个 redis> RPUSH integers 513 (integer) 513 # 编码已改变 redis> OBJECT ENCODING integers "linkedlist"