redis zset 底层采用跳表(skiplist)与字典(dict)组合结构:跳表按 score 有序组织,支持 o(logn) 范围查询和排名;字典以 member 为 key 实现 o(1) 分值查找,二者共享数据、双写同步,兼顾有序性与查询效率。

Redis 用跳表(SkipList)实现有序集合(ZSet),核心是靠“多层有序链表 + 随机层级 + 分数排序”三者协同工作。它不是单靠一层结构完成的,而是把排序、查找、范围查询都压在一套轻量但高效的指针网络上。
节点结构:每个元素带 score 和多层 forward 指针
Redis 中的跳表节点叫 zskiplistNode,关键字段包括:
- score:double 类型,决定元素在集合中的逻辑顺序;
- ele:sds 类型,存实际成员字符串;
-
backward:指向同一层前一个节点,支持反向遍历(比如
ZREVRANGE); -
level[]:动态数组,每层含一个
forward指针和span(跨度值,用于快速计算排名)。
注意:不同节点的层数可以不同——这是跳表“概率性”的体现,也是性能与空间平衡的关键。
跳表整体:头尾指针 + 最大层数 + 长度统计
zskiplist 是跳表容器结构,记录全局信息:
- header / tail:头节点不存数据,只作入口;尾节点便于 O(1) 获取最大元素;
- level:当前跳表最高层数(非固定,随插入动态增长,上限默认 32);
-
length:节点总数,
ZCARD直接返回,不用遍历。
头节点每一层都有 forward 指针,初始都指向 NULL 或 tail,插入时逐层更新。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
为什么能保持有序?靠 score 比较 + 层级索引联动
所有操作都严格按 score 排序,相同 score 时再按 ele 字典序:
- 插入时,先按 score 找到位置,再根据随机算法决定新节点层数(如 P=0.5 概率升一层);
- 查找时,从最高层 header 出发,若 next 节点 score ≤ 目标,就前进;否则下降一层继续;
- 范围查询(如
ZRANGE score1 score2)直接从底层链表某点开始顺序遍历,天然有序、无需额外排序。
这种设计让 ZADD、ZRANK、ZRANGEBYSCORE 全部落在平均 O(log N) 时间内。
实际存储不是纯跳表:它配了一个字典 dict
Redis 的 ZSet 是复合结构:skiplist + dict:
- 跳表负责按 score 排序和范围操作;
- 字典(dict)以 member 为 key、score 为 value,实现 O(1) 的存在性判断和 score 更新(比如
ZSCORE、ZINCRBY); - 两者数据冗余但不冲突——插入/删除时双写,保证一致性。
这也是为什么 ZSet 支持“按成员查分值”和“按分值查成员”两种高效路径。










