【Redis】底层探析 I - Redis 有序集合(ZSet)是如何实现的?

news2024/11/27 2:26:40

目录

ZSet的编码方式

什么是跳跃列表(skiplist)?

ZSet的底层结构

跳跃列表的查询过程


ZSet的编码方式

        Redis中的有序集合zset底层实现采用了两种编码方式:

  • REDIS_ENCODING_SKIPLIST 跳跃列表
  • REDIS_ENCODING_ZIPLIST 压缩列表

        对于不同编码的触发方式/条件,有两个关键因素:

  • zset-max-ziplist-entries 128
  • zset-max-ziplist-value 64

        当有序集合的元素个数 ≥ zset-max-ziplist-entries (128个) ,或每个元素成员的长度≥zset-max-ziplist-value (默认为64字节)时,使用跳跃列表和哈希表作为有序集合的内部实现。

拓展:

        可以通过在Redis配置文件中(redis.conf)中定义使用两种不同编码的时机。

什么是跳跃列表(skiplist)?

        跳跃列表是一种有序的数据结构(有些版本会说是一种随机化的数据结构,这里的随机化是指概率),由William Pugh在论文​​​​​《Skip Lists: A Probabilis ... Trees》中提出。根据不同层级定向引导每一节点指向后续节点,达到快速访问指定节点的目的。跳跃列表在查找指定节点时,平均时间复杂度为O(logN)最坏情况下时间复杂度为O(N)

ZSet的底层结构

/* ZSETs use a specialized version of Skiplists */



///     ele: 当前节点元素,用以存储数据
///     score: 当前元素成员所对应的分数
///     backward:用以指向前驱节点的指针,即回溯指针
///     level:用以表示层级,每一层级对应指向一个指针 forward
///     forward:指向位于表尾方向其他节点的指针。
///     span:当前节点到forward指向的节点所跨越的节点个数。


typedef struct zskiplistNode {
    sds ele;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned long span;
    } level[];
} zskiplistNode;


///     header: 指向头部跳跃表节点的指针。
///     tail:指向尾部跳跃表节点的指针。
///     length:表示跳跃表中的节点总数。
///     level:表示跳跃表中层数最大的节点的层数,表头节点的层数不计算在内。


typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;
    int level;
} zskiplist;

typedef struct zset {
    dict *dict;
    zskiplist *zsl;
} zset;

redis skip list

        从图例和代码中我们不难发现,Redis中zset结构体由zskiplistdict组成,同时zskiplist结构体中包含有跳跃表节点 zskiplistNode跳跃表层级 zskiplistLevel,以此组成了一个双向链表结构

跳跃列表的查询过程

        接下来让我们分析一下跳跃表在查询时的过程。

        在上图中,跳表层级为4层,元素个数为10个,按照自顶向下的顺序进行查找,从顶层(第4层)开始查找元素值17: 

  • 第四层:找到元素值7,但发现7≤17,继续往右找;找到元素值29,但发现7≤29,回溯到上一指向元素值7的指针并向下走一层
  • 第三层:找到元素值25,但发现25≥17,回溯到指向元素值7的指针并向下走一层
  • 第二层:找到元素值16,但发现16≤17,继续往右找;找到元素值17,命中查找值,检索成功

        

        在下一章节,我们将就ZSet中使用的算法和代码实现作进一步阐析,并对性能和背后的数学原理作进一步探究。​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/769953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin获取Fragment中的组件

左边和右边分别是两个不同的Fragment&#xff0c;左边的Fragment中右一个Button组件&#xff0c;目标是想要获取这个组件的id&#xff0c;以便进行将右边的Fragment更改成另一个Fragmeent的操作。 left_fragment.xml <?xml version"1.0" encoding"utf-8&qu…

raid5故障导致上层文件系统不可用的服务器数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器上有两组分别由4块SAS硬盘组建的raid5磁盘阵列&#xff0c;这两组raid5阵列划分LUN并组成LVM结构&#xff0c;格式化为EXT3文件系统。 服务器故障&#xff1a; 一组raid5阵列上的一块硬盘未知原因离线&#xff0c;热备盘上线替换离线…

浅谈医用IT隔离电源系统在医疗场所的应用及设计

安科瑞 华楠 摘 要:结合某工程设计实例对IT系统特点、构成及医疗IT系统相关规范要求进行了详细阐述&#xff0c;并提供了医疗IT系统的工程设计经验&#xff0c;旨在推动医疗IT系统的发展。 关键词:医疗IT系统&#xff0c;隔离变压器&#xff0c;绝缘监测&#xff0c;电击 随…

餐饮行业油烟监控管理系统设计与应用

安科瑞 华楠 摘 要&#xff1a;餐饮油烟污染问题已经成为城市环境污染的重要污染源&#xff0c;本研究的油烟在线监测数据管理信息系统是油烟在线监测数据采集仪的配套软件&#xff0c;用于展现现场端数据采集仪采集的数据&#xff0c;对数据采集仪进行远程控制&#xff0c;以…

Docker安装Nacos2.0.2

docker拉取镜像 docker pull nacos/nacos-server:2.0.2查看镜像 docker images创建容器和运行 docker run -e JAVA_OPTS"-Xms256m -Xmx256m" -e MODEstandalone -e PREFER_HOST_MODEhostname -p 8848:8848 --privilegedtrue --restartalways --name nacos -d naco…

Redis简介(1)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 Redis简介1、NoSQL1.1、什么是NoSQL&#xff1f;1.2、NoSQL 特点…

MySQL事务与事务的隔离级别

MySQL事务与事务的隔离级别 什么事务&#xff1f;事务的特点&#xff08;ACID&#xff09;事务的隔离级别多事务运行的并发问题隔离级别repeatable read&#xff08;可重复读&#xff09;之 MVCC&#xff08;多版本并发控制&#xff09; 并发机制优化 什么事务&#xff1f; 事务…

这些项目管理实际问题,你遇到过几个

大家好&#xff0c;我是老原。 我做了这么久的内容&#xff0c;给大家分享了很多干货、工具还有行业的内容。 今天的文章汇总了粉丝们来私信我的一些实际工作问题&#xff0c;不知道这些问题你熟不熟悉&#xff0c;是否也遇到过&#xff1f; 当然&#xff0c;这不仅是纯粹为…

postgresql 内核源码分析 表锁relation lock的使用,session lock会话锁的应用场景,操作表不再困难

​专栏内容&#xff1a; postgresql内核源码分析 手写数据库toadb 并发编程 个人主页&#xff1a;我的主页 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 表锁介绍 当表打开&#xff0c;或者操作表时&#xff0c;都需要…

spring复习:(44)使用TransactionProxyFactoryBean来实现事务时,事务是怎么提交的?

TransactionAspectSupport类的invokeWithinTransaction方法的最后&#xff1a; 调用commitTransactionAfterReturning,它的代码如下&#xff1a; 调用的commit代码如下&#xff08;AbstractPlatformTransactionManager类里&#xff09;&#xff1a; 其中调用的processCommit…

Altium Designer V23介绍、下载、安装、注册(激活)与汉化

一、Altium Designer简介 Altium Designer 是一款简单易用、原生3D设计增强的一体化设计环境&#xff0c;结合了原理图、ECAD库、规则和限制条件、BoM、供应链管理、ECO流程和世界一流的PCB设计工具。通过原理图设计、电路仿真、PCB绘制编辑、拓扑逻辑自动布线、信号完整性分析…

代理IP、Socks5代理与网络安全:保护隐私与防御威胁的技术探索

目录 一、代理IP技术 二、代理IP保护隐私和网络安全 三、Socks5代理与网络安全 总结 一、代理IP技术 代理IP、Socks5代理IP是与网络安全相关的技术&#xff0c;可以用于保护隐私和防御威胁。下面是对这些技术的探索和解释&#xff1a; 1. 代理IP&#xff1a;代理IP是指通过…

什么是并发(非常详细)

按最简单、最基本的程度理解&#xff0c;并发&#xff08;concurrency&#xff09;是两个或多个同时独立进行的活动。并发现象遍布日常生活&#xff0c;我们可以边走路边说话&#xff0c;左右手同时做出不一样的动作&#xff0c;诸如此类。 计算机系统中的并发 若我们谈及计算…

图书馆管理的好帮手:Librarian Pro Mac 让你的阅读体验更加完美

Librarian Pro Mac是一款功能齐全、易于使用的图书馆管理软件&#xff0c;适用于个人用户、图书馆、学校和其他组织。它提供了丰富的功能和灵活的组织方式&#xff0c;帮助用户轻松管理和浏览他们的图书馆和收藏品。无论你是一个热衷于阅读的个人&#xff0c;还是一个需要管理大…

Linux小程序——进度条【Linux系统编程】

回车换行&#xff1a;回车&#xff08;\r&#xff09;是回到当前光标所在行的最开始&#xff0c;换行(\n)是换到下一行&#xff0c;回车换行就是到下一行的最开始。 缓冲区&#xff1a; 先看第一种&#xff1a;helloworld后面有反斜杠n&#xff0c;那么我们看到的现象是先打印…

01-复杂度2 Maximum Subsequence Sum

思路 比上一题&#xff08;01-复杂度1 最大子列和问题&#xff09;&#xff0c;要多记录几个内容 首尾元素&#xff0c;当前子序列开头元素&#xff0c;当前子序列结尾元素&#xff0c;最佳子序列开头元素&#xff0c;current是否在此处清零&#xff08;则下一个元素是开头元…

2023年四川大学生程序设计竞赛-A.旷野之息

题目描述 Cuber QQ 终于打败盖农救回了塞尔达公主&#xff0c;海拉鲁大地也开始灾后重建。 在统计学中&#xff0c;幂律表示的是两个量之间的函数关系&#xff0c;其中一个量的相对变化会导致另一个量的相应幂次比例的变化&#xff0c;且与初值无关&#xff1a;表现为一个量是…

注释气泡图函数(更新)

之前我们写过一个原创可视化函数Dotplot_anno.R&#xff0c;nature级别图表&#xff1a;一个注释气泡热图函数&#xff08;适用于单细胞及普通数据&#xff09;。主要解决的问题是1) 单细胞基因可视化分组注释。2) Bulk RNA差异基因热图、气泡图。3) 富集分析结果气泡图展示。这…

使用原生Redis命令实现分布式锁

推荐文章&#xff1a; 1、springBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表; ​ 2、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据; 3、java后端接口API性能优化技巧 4、SpringBootMyBatis流式查询,处理大规模数据,提高系统的性能和响应…

【雕爷学编程】Arduino动手做(22)——8X8 LED点阵MAX7219屏8

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#xff0c;这…