参考:<<Redis设计与实现>>

  • 注:这本书是基于Redis3.0版本写的,和后面的版本有点差异

有序集合对象的编码是:

  • ziplist
  • skiplist

一、有序集合对象的编码

1.1 ziplist编码

ziplist编码的有序集合对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),第二个元素保存元素的分值(score)。

压缩列表内的集合元素按分值从小到大排序,分值较小的元素被放置在靠近表头的位置,分值较大的元素被放置在靠近表尾的位置。

示例:

redis> zadd price 8.5 apple 5.0 banana 6.0 cherry

如果price键的值对象使用的是ziplist编码,值对象、以及对象使用的压缩列表如下图所示:

Redis采用ZSet存入JSON字符串 序列化报错 redis zset list_zset


Redis采用ZSet存入JSON字符串 序列化报错 redis zset list_有序集合_02

1.2 skiplist编码

skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表。

(1)zsl跳跃表
zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:

  • 跳跃表节点的object属性保存了元素的成员
  • 跳跃表节点的score属性保存了元素的分值

通过这个跳跃表,程序可以对有序集合进行范围型操作,比如zrank、zrange等命令就是基于跳跃表api来实现的。

(2)dict字典
zset结构中的dict字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素:

  • 字典的键保存了元素的成员
  • 字典的值保存了元素的分值

通过这个字典,程序可以用O(1)复杂度查找给定成员的分值,zscore命令根据这一特性实现的。

注:跳跃表和字典两种数据结构会通过指针共享相同元素的成员和分值。

(3)使用skiplist编码的有序集合对象、对象所使用的zset结构如下图所示:

Redis采用ZSet存入JSON字符串 序列化报错 redis zset list_redis_03

skiplist编码的有序集合对象


Redis采用ZSet存入JSON字符串 序列化报错 redis zset list_跳跃表_04

有序集合对象同时被保存在字典和跳跃表中



二、编码的转换

有序集合对象同时满足以下2个条件时,对象使用ziplist编码,否则使用skiplist编码。

  • 有序集合保存的元素数量小于128个
  • 有序集合保存的所有元素成员的长度都小于64字节

注:上面的128、64阈值是可以修改的,可以查看zset-max-ziplist-entrieszset-max-ziplist-value选项。

redis> config get zset-max-ziplist-entries
1) "zset-max-ziplist-entries"
2) "128"
redis> config get zset-max-ziplist-value
1) "zset-max-ziplist-value"
2) "64"
2.1 ziplist -> skiplist

当使用ziplist编码的对象所需的两个条件任意一个不满足时,都会执行编码转换工作,将原本存储在压缩列表里面的所有集合元素转移到zset里,并将编码改为skiplist。

(1)元素数量超过阈值

临时设置zset-max-ziplist-entries为4进行测试。

redis> config set zset-max-ziplist-entries 4
OK
redis> zadd nums 1 1 2 2 3 3 4 4
(integer) 4
redis> object encoding nums
"ziplist"
redis> zadd nums 5 5
(integer) 1
redis> zcard nums
(integer) 5
redis> object encoding nums
"skiplist"

(2)元素成员过长

临时设置zset-max-ziplist-value为4进行测试。

redis> config set zset-max-ziplist-value 4
OK
redis> zadd strs 1 a 2 bb 3 ccc 4 dddd
(integer) 4
redis> object encoding strs
"ziplist"
redis> zadd strs 5 eeeee
(integer) 1
redis> object encoding strs
"skiplist"