redis中zset的实现
时间: 2025-05-21 10:26:57 浏览: 23
### Redis 中 ZSet 的实现原理
#### 1. ZSet 的定义
ZSet 是 Redis 提供的一种有序集合数据结构,它允许存储键值对形式的元素,并通过分数(score)来维护这些元素的顺序。如果两个元素具有相同的分数,则会根据其成员名称进行字典序排序[^2]。
---
#### 2. 底层数据结构
Redis 使用两种不同的底层编码方式来表示 ZSet 数据结构:`ziplist` 和 `skiplist+dict`。这两种编码的选择取决于 ZSet 的大小以及配置参数:
- **当 ZSet 较小时**(默认情况下,元素数量小于等于 128 并且每个成员长度不超过 64 字节),Redis 会选择更紧凑的 `ziplist` 编码。
- **当 ZSet 较大时** 或者超出上述条件限制时,Redis 则切换到更为高效的 `skiplist+dict` 结构[^3]。
---
#### 3. Skiplist+Dict 的具体实现
在 `skiplist+dict` 模式下,ZSet 主要由两部分组成:
- **Hash Table (Dictionary)**
Hash 表用于快速查找某个成员是否存在及其对应的分数。它的作用类似于索引机制,能够以 O(1) 时间复杂度完成查询操作。
- **Skip List (跳跃表)**
跳跃表负责维持所有成员按分数从小到大的顺序排列。即使存在大量重复分数的情况,跳跃表仍然能保持高效的操作性能,平均时间复杂度为 O(log N)[^4]。
以下是两者的关系描述:
- Dict 对象中的 key 是成员本身,而 value 存储的是该成员的分数。
- SkipList 对象则是一个双向链表加多级指针构成的数据结构,其中每个节点包含成员、分数以及指向其他节点的链接。
---
#### 4. 源码分析
以下是 Redis 中关于 ZSet 的核心源码片段解析:
##### (1)ZSet 节点定义
```c
typedef struct zskiplistNode {
sds ele; // 成员字符串
double score; // 分数值
struct zskiplistNode *backward; // 向前回溯的指针
struct zskiplistLevel {
struct zskiplistNode *forward; // 下一层前进方向上的指针
unsigned long span; // 当前层跨越的距离
} level[];
} zskiplistNode;
```
这段代码展示了单个 ZSet 节点的具体字段含义。每个节点都包含了成员名 (`ele`) 及对应分数 (`score`),并通过多个层次连接形成完整的跳跃表。
---
##### (2)Skiplist 定义
```c
typedef struct zskiplist {
struct zskiplistNode *header, *tail; // 首尾节点
unsigned long length; // 总结点数
int level; // 最高层级数目
} zskiplist;
```
此结构体封装了一个完整的跳跃表实例,记录了头部和尾部位置、总节点计数以及当前最高层级的信息。
---
#### 5. 插入过程概述
当向 ZSet 添加新元素时,Redis 执行以下步骤:
1. 如果目标成员已存在于哈希表中,则更新其分数并调整跳跃表相应位置;
2. 若不存在,则创建新的节点并将之插入至合适的地方,同时同步修改 hash table 和 skip list 的状态[^4]。
---
#### 6. 查询效率评估
由于采用了双保险设计——即既有基于散列函数构建的 dictionary 支持随机访问需求,又有经过精心优化后的 skiplist 来满足范围扫描场景的要求,因此无论是在增删改查还是遍历方面,ZSet 都表现出极高的运行效能。
---
阅读全文
相关推荐


















