Redis中的ZSet是怎么实现的

ZSet(Sorted Set)是Redis中的一种特殊数据结构,内部维护了一个有序字典,其中每个元素都包含成员(member)和double类型的分值(score)。这种结构非常适合实现排行榜功能,如游戏积分榜或网站热度排名。

ZSet实现

Redis的ZSet实现经历了多次演进:

  • 早期采用ziplist(压缩列表)和skiplist(跳跃表)两种结构
  • Redis 5.0引入listpack(紧凑列表)取代ziplist
  • Redis 7.0起完全移除了ziplist

在SkipList 的这种实现还会用dict(字典)

跳表用于维护有序集合,根据元素分值进行排序存储。这种结构支持 O(log n) 时间复杂度的插入、删除和查找操作,确保了高效的有序访问性能。

字典则建立了元素到分值的快速映射关系,以元素为键、分值为值。借助哈希表的特性,字典实现了 O(1) 时间复杂度的各项操作,提供了极高的查询效率。

image.png

ZSet的存储机制

ZSet的存储机制会根据数据规模自动调整:

  • 元素较少时使用ListPack(原ZipList)节约内存
  • 元素增多后自动转换为SkipList以保持有序性和高效范围查询 转换过程会遍历ListPack中的所有元素,
### RedisZSet实现原理 #### 1. ZSet 的定义 ZSetRedis 提供的一种有序集合数据结构,它允许存储键值对形式的元素,并通过分数(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 都表现出极高的运行效能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值