Redis ZSet 类型深度解析:底层数据结构与应用场景

全文目录:

    • 开篇语
    • [🌟 前言](#🌟 前言)
    • [📜 目录](#📜 目录)
    • [💡 什么是ZSet?](#💡 什么是ZSet?)
    • [🧩 ZSet的底层数据结构](#🧩 ZSet的底层数据结构)
      • [1. 小数据量时使用 ziplist](#1. 小数据量时使用 ziplist)
        • [ziplist 结构](#ziplist 结构)
      • [2. 大数据量时使用 skiplist + hash table](#2. 大数据量时使用 skiplist + hash table)
    • [🛠️ ZSet核心操作与复杂度](#🛠️ ZSet核心操作与复杂度)
    • [🚀 ZSet应用场景](#🚀 ZSet应用场景)
      • [1. 排行榜系统](#1. 排行榜系统)
      • [2. 延迟队列](#2. 延迟队列)
      • [3. 社交平台中的热门话题](#3. 社交平台中的热门话题)
      • [4. 任务调度系统](#4. 任务调度系统)
    • [🔍 ZSet在Redis内存中的优化](#🔍 ZSet在Redis内存中的优化)
    • [🎉 总结](#🎉 总结)
    • 文末

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

🌟 前言

大家在使用Redis时,可能会接触到一种非常有用的数据结构:有序集合(ZSet) 。与普通集合(Set)相比,ZSet不仅能够存储不重复的元素,还可以为每个元素关联一个评分(Score),并通过这个评分实现自动排序。这样的设计使得ZSet在排行榜、优先级队列等场景中广泛应用。那么,ZSet是如何在内部实现高效的排序和存储的呢?今天我们深入剖析ZSet的底层结构,一探究竟!💡


📜 目录

  1. 💡 什么是ZSet?
  2. 🧩 ZSet的底层数据结构
  3. 🛠️ ZSet核心操作与复杂度
  4. 🚀 ZSet应用场景
  5. 🔍 ZSet在Redis内存中的优化
  6. 🎉 总结

💡 什么是ZSet?

在Redis中,ZSet (Sorted Set)是一种有序的集合 。它和普通的Set一样,不允许元素重复,但与Set不同的是,ZSet中的每个元素都有一个分数(Score)。ZSet依据这个分数对元素进行排序,并支持根据分数范围进行快速查询。

ZSet 的数据结构支持以下特性:

  • 去重:元素不可重复。
  • 排序:元素按分数自动排序。
  • 范围查询:支持通过分数或排名范围进行快速查询。

ZSet 实现了自动排序功能,且可以灵活地根据需求来取出分数范围或排名范围内的元素,非常适合实现排行榜和优先级队列等功能。


🧩 ZSet的底层数据结构

Redis 中的 ZSet 底层数据结构主要由 跳表(Skip List)哈希表(Hash Table) 共同实现。根据数据量大小和存储需求,Redis会在不同场景下切换底层实现结构,以平衡内存和性能。

1. 小数据量时使用 ziplist

ziplist(压缩列表)是一种压缩后的双向链表结构,用于存储少量数据的 ZSet,以减少内存开销。当以下条件同时满足时,ZSet 使用 ziplist:

  • 元素数量 :小于 zset-max-ziplist-entries(默认128)。
  • 分数大小 :分数的字符串长度小于 zset-max-ziplist-value(默认64字节)。
ziplist 结构

在 ziplist 中,数据是以压缩格式连续存储的,通过减少内存分配的碎片化来降低内存使用。其特点如下:

  • 连续存储:所有元素和分数的存储在一段连续的内存中。
  • 空间效率高:适用于少量数据的场景。
  • 读写性能较低:ziplist 中每次插入都需调整位置,适合存储少量静态数据。

注意:ziplist 的效率在数据量较小时表现较优,但不适用于大数据量的动态操作。

2. 大数据量时使用 skiplist + hash table

当数据量较大或分数较长时,Redis会自动切换为 跳表(skiplist)+ 哈希表(hash table) 的结构,这种组合可以兼顾插入、删除的速度与有序性。

跳表(skiplist)

跳表是一种分层链表结构,通过多级索引加速查找,是 ZSet 排序的核心组件。

  • 层级设计:跳表包含多层链表,每一层是对下层的索引,层级越高跨度越大。
  • 插入与删除:插入、删除时间复杂度为 O(log N)。
  • 排序:跳表按分数从低到高进行排序,通过分层索引快速定位元素位置。
哈希表(hash table)

哈希表在 ZSet 中用于存储元素和分数的映射关系,便于查找元素。

  • 查找效率高:Hash Table 中的查找复杂度为 O(1)。
  • 数据一致性:Hash Table 存储键值对确保每个元素的分数准确,跳表则维护元素的有序性。

🛠️ ZSet核心操作与复杂度

ZSet 提供了多种操作,以便对有序数据进行快速访问。常见操作及其时间复杂度如下:

操作 命令 时间复杂度 说明
插入/更新 ZADD O(log N) 插入或更新分数
删除元素 ZREM O(log N) 删除指定元素
获取排名 ZRANK / ZREVRANK O(log N) 获取指定元素的排名
获取分数范围 ZRANGEBYSCORE O(log N + M) 获取分数在指定范围内的元素
获取元素范围 ZRANGE / ZREVRANGE O(log N + M) 按排名获取元素,支持倒序
计数 ZCOUNT O(log N) 统计指定分数范围的元素数量
取最大/最小值 ZPOPMAX / ZPOPMIN O(log N) 获取并删除最大/最小分数的元素

注意N 为集合的元素数量,M 为范围查询的结果数量。跳表和哈希表的组合让这些操作在 ZSet 中变得非常高效!


🚀 ZSet应用场景

ZSet的有序和范围查询能力使其成为多种应用场景的理想选择。以下是一些典型的使用场景:

1. 排行榜系统

ZSet 的有序性和按分数排序的特性非常适合实现排行榜。比如游戏排行榜中,玩家的积分作为分数,玩家名作为成员,通过 ZSet 可以实现排名查询、范围查询等操作。

  • ZADD:添加或更新玩家的分数。
  • ZRANK / ZREVRANK:获取玩家的排名。
  • ZRANGE / ZREVRANGE:获取排名前几名的玩家。

2. 延迟队列

通过 ZSet 可以构建一个延迟队列,消息的分数设为到期时间戳。查询到期消息时,只需查找分数小于当前时间的元素。

  • ZADD:将消息及其执行时间添加到队列。
  • ZRANGEBYSCORE:获取即将到期的消息。
  • ZREM:执行后从队列中删除。

3. 社交平台中的热门话题

在社交媒体应用中,通过 ZSet 可以实现"热门话题"榜单,话题作为成员,热度分数作为评分值。定期更新 ZSet,可以动态展示热门话题。

  • ZINCRBY:增加话题热度。
  • ZRANGE / ZREVRANGE:获取热度排行靠前的热门话题。

4. 任务调度系统

ZSet 还可用于任务调度,将任务按优先级或到期时间排序,以决定任务的执行顺序。


🔍 ZSet在Redis内存中的优化

Redis对ZSet的内存使用进行了多项优化,包括:

  1. ziplist优化:在小数据量下,ZSet 使用 ziplist 实现,减少内存开销。
  2. skiplist与hash table的组合:对于大数据量使用跳表+哈希表,确保性能与内存使用的平衡。
  3. 分数存储压缩:ZSet 中的分数存储采用压缩算法,在性能和空间上达到优化。

小贴士:我们可以通过配置 zset-max-ziplist-entrieszset-max-ziplist-value 来控制 Redis 切换 ZSet 底层数据结构的条件,以适应不同的应用场景。


🎉 总结

Redis的ZSet数据结构通过跳表和哈希表的组合实现了高效的排序和查询,非常适合处理需要排序或优先级的场景。无论是排行榜、延迟队列还是热门话题,ZSet 都能轻松应对。掌握其底层实现与常见操作,我们可以在实际应用中发挥 ZSet 的最大潜力!

希望这篇解析能帮助你更好地理解和使用Redis的ZSet!Happy Coding!

... ...

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

相关推荐
先鱼鲨生11 分钟前
排序【数据结构】【算法】
数据结构·算法·排序算法
不爱学习的YY酱15 分钟前
【Linux】<共享内存应用>——模拟实现不同进程把hello字符对<共享内存文件对象>的放入和取出操作
linux·数据库·nosql
疯狂的代M夫29 分钟前
数据结构 【带环链表2】
数据结构·链表
网络安全指导员29 分钟前
SQL注入的那些面试题总结
数据库·sql·安全·web安全·系统安全
daily_233334 分钟前
数据结构——小小二叉树第二幕(二叉树链式结构的实现以及二叉树的遍历)超详细!!!
数据结构·c++
奈斯ing41 分钟前
【Oracle篇】SQL性能优化实战案例(从15秒优化到0.08秒)(第七篇,总共七篇)
运维·数据库·sql·oracle·性能优化
Karoku0661 小时前
【企业级分布式系统】ELK-企业级日志分析系统
运维·数据库·redis·mysql·elk·缓存
小小宇宙中微子1 小时前
mysql 命名约束
数据库·sql·oracle
小小白白蛆1 小时前
剑指offer JZ51 数组中的逆序对
数据结构·算法·排序算法
是店小二呀1 小时前
【C++】右值引用与移动语义详解:如何利用万能引用实现完美转发
c++·redis