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