Redis有序集合对象(Zset)使用ziplist和skiplist

标题首先明确一下几点基本常识:

  • Redis常见的5种数据类型:String(字符串)、List(列表)、Hash(哈希)、Set(集合)、ZSet(有序集合),这五种常见的数据类型,本质上对应着五种对象,即字符串对象、列表对象、哈希对象、集合对象、有序集合对象。
  • 在Redis中,任意一个对象都具有五种属性

[1] type ====> 类型对应基本数据类型。例如Redis_String 对应字符串,Redis_List对应列表
[2] encoding ====> 编码。编码方式决定了对象的底层的数据结构,一个对象至少有两种编码方式
[3] prt ====> 指针。指向由编码决定的数据结构,数据结构中往往包含有所存的数据
[4] refcount ====> 引用计数。这个属性主要是为了实现redis中的内存回收机制
[5] lru ====> 最近最少使用。用来解决对象的空转时长,同时也会被用于当缓冲达到最大值,再向其中添加数据时,应该删除什么数据。

有序结合(ZSet)对象详解

上述说过,一个对象的底层的数据结构是由对象的编码方式决定的,而ZSet的编码方式有两种

  • ziplist
  • skiplist
    上述两种数据结构的底层实现见书籍 《redis设计与实现》。
    有序结合底层s

ZipList

使用压缩连表时,要保证集合中的数据有序,会将key放在前面一位,然后将key所对应value放在key的后一位。这样就能够保证集合的有序。
在这里插入图片描述

SkipList

使用跳跃链表时,由于跳跃链表本来就是有序的,直接使用即可。
跳表数据结构见《Redis设计与实现》P39

当有序集合对象同时满足以下两个条件时,对象使用压缩链表编码:

  • 有序集合保存的元素数量小于128个;
  • 有序集合保存的所有元素成员的长度都小于64字节;

如果不满足上述两个条件,那么ZipList会转化为SkipList,同时,当后面的SkipList的元素数量和元素成员的长度满足要求时,也不会回退为ZipList。

重点

当使用SkipList实现ZSet时,ptr所指向的zset数据结构中包含了一个skiplist和dict结构。其中dict结构中创建了一个从SkipList对象到score的映射。通过dict可以实现O(1)时间复杂度查找key所对应的value。

那么为什么不直接使用字典或者skipList实现Zset呢?

  • 当直接使用字典的时候,虽然可以做到查询key-value的时间复杂度O(1),但是字典本身是无序的,要排序至少也需要O(Nlog(N))。
  • 当直接使用SkipList时,虽然可以做到有序,但是查询key-value至少也需要O(logN)。
<think>我们正在讨论Redis有序集合Zset)。根据引用,ZsetRedis中的一种数据结构,它结合了集合排序的特性。每个元素都有一个分数(score),用于排序。Zset的底层实现有两种:ziplist(压缩列表)skiplist(跳表)。当元素数量少且元素值小时,使用ziplist以节省内存;否则使用skiplist以支持高效的操作。使用场景包括排行榜、带权重的消息队列、时间轴等。接下来,我将按照以下结构组织回答:1.Zset的基本特性2.底层数据结构ziplistskiplist)3.常用命令4.使用场景5.相关问题注意:引用中提到了Zset的底层结构、命令使用场景,我们将综合这些信息。</think>### Redis Zset 有序集合详解 #### 一、核心特性与数据结构 Zset有序集合)是 Redis 特有的数据结构,兼具 **集合去重** **有序存储** 双重特性: - **元素唯一性**:成员值不可重复(类似 Set) - **排序能力**:通过关联的 `score`(双精度浮点数)实现排序 - **底层实现**: - **压缩列表 (ziplist)** 当元素数量 ≤ `zset-max-ziplist-entries`(默认128)且元素值 ≤ `zset-max-ziplist-value`(默认64字节)时启用,内存占用极低[^5]。 - **跳表 (skiplist) + 字典 (dict)** 大数据量时采用,跳表提供 $O(\log n)$ 的排序操作,字典提供 $O(1)$ 的元素查找[^2]。 > **数据结构对比**: > | 结构类型 | 时间复杂度 | 适用场景 | > |---------|-----------|---------| > | 压缩列表 | $O(n)$ | 小数据量、内存敏感场景 | > | 跳表 | 插入$O(\log n)$/查找$O(\log n)$ | 大数据量、高频操作 | #### 二、核心操作命令 ```bash # 添加元素(可批量) ZADD key [NX|XX] [CH] [INCR] score member [score member ...] # 示例:添加学生成绩 ZADD student_scores 92 "Alice" 85 "Bob" 96 "Charlie" # 范围查询(按score排序) ZRANGE key start stop [WITHSCORES] # 升序 ZREVRANGE key start stop [WITHSCORES] # 降序 # 示例:查询前三名 ZREVRANGE student_scores 0 2 WITHSCORES # 条件查询(按score范围) ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] # 示例:查询90分以上学生 ZRANGEBYSCORE student_scores 90 +inf WITHSCORES # 排名与分数操作 ZRANK key member # 升序排名(从0开始) ZSCORE key member # 获取分数 ZINCRBY key increment member # 分数增减 ``` #### 三、核心应用场景 1. **实时排行榜** - 游戏玩家积分榜:`ZADD` 更新分数,`ZREVRANGE` 获取TOP10 - 电商热销商品:`ZINCRBY` 实现销量计数 ```bash ZINCRBY hot_products 1 "iPhone15" # 每次购买增加销量 ``` 2. **延迟队列** 利用 `score` 存储执行时间戳: ```bash ZADD delay_queue 1640995200 "task1" # 2022-12-31 00:00执行 # 定时扫描:获取到期任务 ZRANGEBYSCORE delay_queue 0 1640995199 WITHSCORES ``` 3. **带权重调度系统** - 优先任务调度:高优先级任务设置更高 `score` - 负载均衡:`score` 表示节点负载,选择负载最低节点 4. **时间轴数据** - 社交平台动态:`score` 存储发布时间戳 - 日志时序存储:`score` 为日志生成时间 #### 四、性能优化实践 1. **内存控制**: - 小数据量时优先使用压缩列表(调整 `zset-max-ziplist-entries` `zset-max-ziplist-value`) - 大数据量时启用内存碎片整理 2. **查询优化**: - 避免 `ZRANGE` 全量遍历,使用 `LIMIT` 分页 - 范围查询优先用 `ZRANGEBYSCORE` 替代 `ZRANGE` + 过滤 3. **跳表优势**: - 相比 B+ 树:实现更简单,区间查询高效 - 相比红黑树:范围查询更优,并发扩展性好[^2] > **场景选型决策**: > ```mermaid > graph TD > A[需要排序+去重?] -->|是| B{数据规模} > B -->|小数据| C[Zset+压缩列表] > B -->|大数据| D[Zset+跳表] > A -->|否| E[选择Set/Hash] > ``` #### 五、典型应用案例 - **微博热搜榜**:`ZINCRBY` 统计搜索次数,`ZREVRANGE` 生成TOP50 - **滴滴派单系统**:`score` = 司机距离 × 服务质量,`ZRANGE` 获取最优司机 - **股票价格监控**:`ZADD` 更新实时股价,`ZRANGEBYSCORE` 触发价格警报 --- ### 相关问题 1. 如何设计一个支持实时更新的游戏玩家战力排行榜?ZsetRedis Stream 如何选择? 2. Zset 的跳表实现中,如何平衡查询性能内存占用?插入操作的具体步骤是什么? 3. 在使用 Zset 作为延迟队列时,如何解决重复消费消息丢失问题? 4. 当 Zset 的元素数量超过百万级时,有哪些性能优化策略? 5. ZsetRedis 的另一种有序数据结构 Sorted Set 有何区别?在不同场景下如何选择?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值