美文网首页
Redis - zset底层数据结构实现

Redis - zset底层数据结构实现

作者: kyo1992 | 来源:发表于2021-04-08 08:17 被阅读0次

    前言

    zset为有序的,自动去重的集合数据类型,zset数据结构底层实现为字典(dict) + 跳表(skiplist),当数据比较少时,用ziplist编码结构存储,element和score各占一个entry.
    ele1 - score1 - ele2 - score2 ...
    redis.conf有以下两个参数控制

    # Similarly to hashes and lists, sorted sets are also specially encoded in
    # order to save a lot of space. This encoding is only used when the length and
    # elements of a sorted set are below the following limits:
    zset-max-ziplist-entries 128  
    zset-max-ziplist-value 64   
    

    zset-max-ziplist-entries 128 // 元素个数超过128,将用skiplist编码
    zset-max-ziplist-value 64 // 单个元素大小超过64byte,将用skiplist编码

    实验

    127.0.0.1:6379> zadd a-zset 100 a 200 b 150 c
    (integer) 3
    127.0.0.1:6379> zrange a-zset 0 -1 withscores
    1) "a"
    2) "100"
    3) "c"
    4) "150"
    5) "b"
    6) "200"
    127.0.0.1:6379> object encoding a-zset
    "ziplist"
    

    加入的元素个数较少,且key的长度小于64byte时,使用ziplist有序存储元素。

    127.0.0.1:6379> zadd a-zset 100 aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffggggg 200 b 150 c
    (integer) 3
    127.0.0.1:6379> object encoding a-zset
    "skiplist"
    

    往zset添加一个长度为65byte的key,此时底层选用skiplist存储元素。

    zet数据结构

    typedef struct zset{
        dict *dict;
        zskiplist *zsl;
    }zset
    
    typedef struct zskiplist{
        struct zskiplistNode *header, *tail;
        unsigned long length;
        int level;
    } zskiplist;
    
    typedef struct zskiplistNode{
        sds ele;      // 元素key
        double score;    // 元素分值
        struct zskiplistNode * backward;
        struct zskiplistLevel{
              struct zskiplistNode *forward;    // 指向前一个节点
              unsigned long span;    // 记录当前层元素之间的跨度,可以快速查询到排名
      } level[]  // 层高,表示该节点在每一层的情况
    }zskiplistNode;
    

    利用dict可以以O(1)时间复杂度判断某个key'是否存在,以及取出key的分值。
    skiplist是一个有多个索引层,一个数据层的数据结构,索引层和数据层都是有序的双向列表。
    每个索引层的元素,都有两个指针字段,分别指向当前索引层下一个元素,以及下一索引层的本元素。
    索引层1: 23 ----------- 52 ----------- 65 --------------- 76 ---------- null
    索引层2: 23 ----43---- 52 ----59---- 65 -----70------- 76 ----84---- null
    数据层: 23 -32-43-47- 52 -55-59-61- 65 --67-70-74- 76 -79-84--86-null

    N: 节点数量
    index: 1 --- N/2^1
    index: 2 --- N/2^2
    index: 3 --- N/2^3
    index: k --- N/2^k
    顶层只有两个元素: 2^k = N / 2 --- > k = log2(N-1)
    时间复杂度:每一个索引层最多查找两次,层数为 log2(N-1) ---> 2 * log2(N-1) = log(N),与二分查找时间复杂度一样。

    相关文章

      网友评论

          本文标题:Redis - zset底层数据结构实现

          本文链接:https://www.haomeiwen.com/subject/jipykltx.html