Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis 跳表

Redis 跳表(Skip List)原理实现

作者:xiaoyu❅

跳表是zset有序集合的底层实现之一,本文主要介绍了Redis 跳表(Skip List)原理实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

引言:为什么 Redis 选择跳表?

在有序集合(ZSET)的实现中,Redis 开发者面临一个关键抉择:如何在高性能读写和代码简洁性之间找到平衡?传统平衡树(如红黑树)虽然能保证 O(logN) 时间复杂度,但实现复杂且难以支持范围查询。跳表(Skip List) 以媲美平衡树的性能、极简的实现(约 200 行代码)和天然支持范围查询的特性,成为 Redis ZSET 的核心数据结构。本文将深入剖析跳表的实现细节与 Redis 的工程优化。

一、跳表核心思想:概率化的多层索引

1.1 从链表到跳表的进化

1.2 跳表结构可视化

Level 3: Head -> 37 --------------------------> 99 -> NULL  
Level 2: Head -> 37 -------> 71 -------> 99 -> NULL  
Level 1: Head -> 37 -> 55 -> 71 -> 85 -> 99 -> NULL  
Level 0: Head -> 37 -> 55 -> 71 -> 85 -> 99 -> NULL  

关键特性

每个节点随机生成层数(Redis 最大层数 64)

高层索引跨越更多节点,加速搜索

底层链表存储完整数据

二、Redis 跳表实现深度解剖

2.1 数据结构定义(redis.h)

// 跳表节点
typedef struct zskiplistNode {
    sds ele;                          // 成员对象(SDS字符串)
    double score;                     // 排序分值
    struct zskiplistNode *backward;   // 后退指针(双向链表)
    struct zskiplistLevel {
        struct zskiplistNode *forward; // 前进指针
        unsigned long span;            // 跨度(用于排名计算)
    } level[];                        // 柔性数组,层级随机生成
} zskiplistNode;

// 跳表结构
typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;             // 节点总数
    int level;                        // 当前最大层数
} zskiplist;

设计亮点

2.2 关键操作源码解析

2.2.1 节点层数生成算法

// redis.h 源码节选
int zslRandomLevel(void) {
    int level = 1;
    // 0xFFFF 对应 1/4 概率提升层级(基于位运算优化)
    while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
        level += 1;
    return (level < ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

数学原理

2.2.2 插入节点流程(zslInsert)

2.2.3 范围查询(ZRANGEBYSCORE)

三、性能分析与优化策略

3.1 时间复杂度对比

操作跳表(平均)跳表(最坏)平衡树
插入O(logN)O(N)O(logN)
删除O(logN)O(N)O(logN)
查找O(logN)O(N)O(logN)
范围查询O(logN + M)O(N)O(logN + M)

:跳表最坏情况(所有节点高度相同)概率极低(例如 1亿节点出现概率为 1/(2^50))

3.2 内存占用分析

3.3 调优参数

四、跳表在 Redis 中的应用场景

4.1 有序集合(ZSET)

元素数量 > 128 或 元素长度 > 64 字节 时,ZSET 内部使用跳表

支持操作

4.2 集群元数据管理

用于维护槽位(slot)与节点的映射关系

五、跳表 vs 平衡树:工程角度的选择

维度跳表红黑树
实现复杂度约 200 行代码约 500 行代码
范围查询天然支持(链表特性)需要额外遍历
并发控制更易实现无锁优化需要复杂锁机制
调试难度可视化调试友好树旋转逻辑难追踪

Redis 作者 Antirez 的评价:“跳表在理论上不如平衡树优雅,但实际工程中更简单、更快,尤其适合需要范围查询的场景。”

总结:

跳表的精妙之处在于 用概率换结构,通过随机化层级分布避免复杂的再平衡操作。这种“以空间换时间” + “以概率换简单性”的设计哲学,在分布式系统开发中具有重要借鉴意义。理解跳表不仅有助于掌握 Redis 源码,更能启发我们思考如何在高性能与可维护性之间找到平衡。

到此这篇关于Redis 跳表(Skip List)原理实现的文章就介绍到这了,更多相关Redis 跳表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文