Redis ZSet底层结构与插入元素的过程

Redis Zset由哈希表和跳表构成。哈希表记录了member与score的映射,可以快速查询member的score;跳表有序存储元素,用于范围查询。

跳表的实现原理

跳表简单来说是一个多层链表。Redis的跳表有一个链表组成,每个节点内部包含元素值、score、后退指针和level数组,level数组记录了多层索引。

typedef struct zskiplistNode {
    //Zset 对象的元素值
    sds ele;
    //元素权重值
    double score;
    //后退指针
    struct zskiplistNode *backward;
  
    //节点的level数组,保存每层上的前向指针和跨度
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned long span;
    } level[];
} zskiplistNode;

跳表的形态如图。每个大方框代表一个zskiplistNode,蓝色的方框代表level数组,level数组指向了下一个zskiplistNode节点。

插入元素的过程

  1. 搜索元素插入的位置
    redis会记录每层能够达到的最右的节点,用数组update记录。
    算法会for循环从上到下遍历。指针x首先从最高层节点出发。如果右边节点不为空且score小于给定值,则x右移直到右边的节点为空或者score大于给定值,此时会将当前的x的指针记录到数组中。后续遍历不用从头开始,直接从x的位置继续查找下一层。最终得到每一层能够达到的最右的节点。
    比如:
    插入元素9,前五层能够达到的最右边的节点为5、8、8.5、8.5、8.5

  2. 计算一个随机的层数
    Redis为当前元素随机分配一个层数,比如4层。

  3. 插入并更新span
    插入时,根据数组中的记录,将每一层节点的对应的level的forward指针指向新插入的节点,沿途还会更新每个节点的span。update[0]指向9,而9的backward指向update[0]对应的节点。

posted @ 2025-05-15 21:29  Nammonco  阅读(87)  评论(0)    收藏  举报