Redis笔记之有序集合对象

2021-08-28  本文已影响0人  slxixiha

集合对象的编码可以是ziplist或者skiplist。

ziplist编码类型

每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点则保存元素的分值。

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

skiplist编码类型

skiplist编码并不是只使用skiplist,而是skiplist和字典的集合,该集合命名为zset,定义见下:

typedef struct zset {
    dict *dict;
    zskiplist *zsl;
} zset;

zset结构中的zsl跳跃表按照分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:跳跃表节点的object属性保存了元素的成员,而跳跃表节点的score属性则保存了元素的分值。通过这个跳跃表,程序可以对有序集合进行范围操作,例如zrank、zrange等命令。

zset中的dict字典,为有序集合创建了一个从成员到分值的映射,字典的键保存了元素的成员,而字典的值则保存了元素的分值。通过这个字典,程序可以用O(1)复杂度查找给定成员的分值,zscore就是通过这个特性实现的。

看起来两个结构似乎有了两份数据,但是实际上两个对象会通过指针共享数据,所以不存在冗余数据的问题。

这里两种结构的混合使用实际上就是一种空间换时间的典型案例。

对象类型的结构图
对象中不同类型的适用条件:

只有同时满足以下两个条件时才会使用ziplist编码:

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

不能满足以上条件的有序集合对象都将使用skiplist编码,这两个上限都可修改

通过以下命令验证:

127.0.0.1:6379> eval "for i=1, 128 do redis.call('zadd', KEYS[1], i, i) end" 1 znum
(nil)
127.0.0.1:6379> zcard znum
(integer) 128
127.0.0.1:6379> object encoding znum
"ziplist"
127.0.0.1:6379> zadd znum 3.14 pi
(integer) 1
127.0.0.1:6379> zcard znum
(integer) 129
127.0.0.1:6379> object encoding znum
"skiplist"

127.0.0.1:6379> zadd  blah 1.9 www
(integer) 1
127.0.0.1:6379> object encoding blah
"ziplist"
127.0.0.1:6379> zadd blah 2.0 ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
(integer) 1
127.0.0.1:6379> object encoding blah
"skiplist"
上一篇 下一篇

猜你喜欢

热点阅读