实战探讨:为什么 Redis Zset 选择跳表?

在了解了跳表的原理和实现后,一个常见的问题(尤其是在面试中)随之而来:为什么像 Redis 的有序集合 (Zset) 这样的高性能组件会选择使用跳表,而不是大家熟知的平衡树(如红黑树)呢?

对于这个问题,Redis 的作者 Salvatore Sanfilippo (@antirez) 曾给出过解释,主要可以归纳为以下几点:

  1. 内存效率与灵活性 (Memory Efficiency & Flexibility):

    • 跳表并非特别消耗内存。其内存占用可以通过调整节点提升的概率 p​ 来控制。通过选择合适的 p​ 值,可以使得跳表的平均内存占用低于某些平衡树。
  2. 高效的范围查询与缓存局部性 (Efficient Range Queries & Cache Locality):

    • Zset 经常需要执行 ZRANGE​ (按排名范围查询) 或 ZREVRANGE​ (按排名反向范围查询) 操作,这本质上是在有序结构上进行一段连续元素的遍历。
    • 跳表的最底层 (Level 0) 是一个有序链表。执行范围查询时,只需定位到范围的起始点,然后沿着 Level 0 的链表顺序遍历即可。这种顺序访问模式具有良好的缓存局部性 (cache locality),与平衡树的中序遍历相比,至少同样好,甚至可能更好。
  3. 实现的简单性与易扩展性 (Implementation Simplicity & Extensibility):

    • 跳表的实现、调试相比平衡树(尤其是红黑树)要简单得多。平衡树复杂的旋转和重新平衡逻辑很容易出错。
    • 跳表的简单性也带来了更好的可扩展性。@antirez 提到,得益于跳表的简洁,他很容易地集成了一个社区贡献的补丁,通过对跳表进行少量修改,就在 O(log N) 时间内实现了 ZRANK​ (获取成员排名) 的功能。

进一步解读与补充:

  • 内存占用对比:

    • 平衡树(如红黑树)每个节点通常需要存储 2 个指向子节点的指针,以及可能的父指针和颜色信息。
    • 跳表每个节点包含的指针数目是可变的,取决于它提升的层数。平均来说,每个节点包含的指针数量为 1 / (1 - p)​(其中 p​ 是节点提升一级概率)。在 Redis 的实现中,p​ 通常取 0.25 (1/4),这意味着平均每个节点大约有 1 / (1 - 0.25) = 1.33​ 个 right​ 指针(再加上 down​ 指针和可能的 backward​ 指针,但核心指向下一节点的指针数平均较少)。这使得跳表在内存使用上具有一定的灵活性和潜在优势。
  • 范围查询的易实现性:

    • 如 @antirez 所说,跳表执行范围查询非常自然。找到范围起点后,沿着最底层的链表顺序遍历即可,逻辑简单清晰。
    • 平衡树执行范围查询,需要先找到范围起点,然后执行中序遍历来依次访问后续节点,直到超出范围终点。虽然中序遍历本身不复杂,但在某些实现中,高效地进行部分中序遍历可能需要额外的辅助结构或递归,相对跳表的直接链表遍历要稍微复杂一些。此外,跳表 Level 0 的节点在内存中可能是物理上更连续的(如果内存分配器配合),有利于缓存;而树的中序遍历则可能在内存地址上跳跃。
  • 实现与维护成本:

    • 这一点对于像 Redis 这样需要高性能、高稳定性且持续迭代的项目至关重要。更简单的实现意味着更少的 Bug、更快的开发迭代速度和更低的维护成本。平衡树,特别是红黑树,其插入和删除操作涉及多种情况的判断、旋转和重新染色,逻辑复杂,容易出错。

总结来说,Redis Zset 选择跳表是基于其在内存占用、范围查询性能与实现简洁性之间取得的良好平衡。 对于 Zset 这种既需要快速单点查找/更新,又需要高效范围遍历的场景,跳表提供了一个非常实用且工程上更优的解决方案。

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

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

相关文章

数据结构-线性结构(链表、栈、队列)实现

公共头文件common.h #define TRUE 1 #define FALSE 0// 定义节点数据类型 #define DATA_TYPE int单链表C语言实现 SingleList.h #pragma once#include "common.h"typedef struct Node {DATA_TYPE data;struct Node *next; } Node;Node *initList();void headInser…

高中数学联赛模拟试题精选学数学系列第3套几何题

△ A B C \triangle ABC △ABC 的内切圆 ⊙ I \odot I ⊙I 分别与边 B C BC BC, C A CA CA, A B AB AB 相切于点 D D D, E E E, F F F, D D ′ DD DD′ 为 ⊙ I \odot I ⊙I 的直径, 过圆心 I I I 作直线 A D ′ AD AD′ 的垂线 l l l, 直线 l l l 分别与 D E DE…

使用 ossutil 上传文件到阿里云 OSS

在处理文件存储和传输时,阿里云的对象存储服务(OSS)是一个非常方便的选择。特别是在需要批量上传文件或通过命令行工具进行文件管理时,ossutil提供了强大的功能。本文将详细说明如何使用 ossutil 上传文件到阿里云 OSS&#xff0c…

DeepSeek与MySQL:开启数据智能新时代

目录 一、引言:技术融合的力量二、DeepSeek 与 MySQL:技术基石2.1 DeepSeek 技术探秘2.2 MySQL 数据库深度解析 三、DeepSeek 与 MySQL 集成:从理论到实践3.1 集成原理剖析3.2 集成步骤详解 四、应用案例:实战中的价值体现4.1 电商…

WebAPI项目从Newtonsoft.Json迁移到System.Text.Json踩坑备忘

1.控制器层方法返回类型不能为元组 控制器层方法返回类型为元组时,序列化结果为空。 因为元组没有属性只有field,除非使用IncludeFields参数专门指定,否则使用System.Text.Json进行序列化时不会序列化field var options new JsonSerializ…

202553-sql

目录 一、196. 删除重复的电子邮箱 - 力扣(LeetCode) 二、602. 好友申请 II :谁有最多的好友 - 力扣(LeetCode) 三、176. 第二高的薪水 - 力扣(LeetCode) 一、196. 删除重复的电子邮箱 - 力扣…

Spring Boot的GraalVM支持:构建低资源消耗微服务

文章目录 引言一、GraalVM原生镜像技术概述二、Spring Boot 3.x的GraalVM支持三、适配GraalVM的关键技术点四、构建原生镜像微服务实例五、性能优化与最佳实践总结 引言 微服务架构已成为企业应用开发的主流模式,但随着微服务数量的增加,资源消耗问题日…

pip 常用命令及配置

一、python -m pip install 和 pip install 的区别 在讲解 pip 的命令之前,我们有必要了解一下 python -m pip install 和 pip install 的区别,以便于我们在不同的场景使用不同的方式。 python -m pip install 命令使用 python 可执行文件将 pip 模块作…

Vue高级特性实战:自定义指令、插槽与路由全解析

一、自定义指令 1.如何自定义指令 ⑴.全局注册语法 通过 Vue.directive 方法注册,语法格式为: Vue.directive(指令名, {// 钩子函数,元素插入父节点时触发(仅保证父节点存在,不一定已插入文档)inserted(…

本地大模型编程实战(32)用websocket显示大模型的流式输出

在与 LLM(大语言模型) 对话时,如果每次都等 LLM 处理完毕再返回给客户端,会显得比较卡顿,不友好。如何能够像主流的AI平台那样:可以一点一点吐出字符呢? 本文将模仿后端流式输出文字,前端一块一块的显示文字…

人工智能-深度学习之卷积神经网络

深度学习 mlp弊端卷积神经网络图像卷积运算卷积神经网络的核心池化层实现维度缩减卷积神经网络卷积神经网络两大特点卷积运算导致的两个问题:图像填充(padding)结构组合问题经典CNN模型LeNet-5模型AlexNet模型VGG-16模型 经典的CNN模型用于新…

蓝桥杯电子赛_继电器和蜂鸣器

目录 一 前言 二 继电器和蜂鸣器实物 三 分析部分 (1)bsp_init.c (2)蜂鸣器和继电器原理图 (3)ULN2003 (4)他们俩所连接的锁存器 四 代码 在这里要特别说一点!&…

仿腾讯会议——主界面设计创建房间加入房间客户端实现

1、实现腾讯会议主界面 2、添加Qt类WeChatDialog 3、定义创建会议和加入会议的函数 4、实现显示名字、头像的函数 调用函数 5、在中间者类中绑定函数 6、实现创建房间的槽函数 7、实现加入房间的槽函数 8、设置界面标题 9、服务器定义创建和进入房间函数 10、服务器实现创建房间…

网络编程初识

注:此博文为本人学习过程中的笔记 1.socket api 这是操作系统提供的一组api,由传输层向应用层提供。 2.传输层的两个核心协议 传输层的两个核心协议分别是TCP协议和UDP协议,它们的差别非常大,编写代码的风格也不同&#xff0c…

【质量管理】现代TRIZ问题识别中的功能分析——功能模型

功能模型的定义 功能模型是对工程系统进行功能分析的一个阶段,目的是建立工程系统的功能模型。功能模型描述了工程系统和超系统组件的功能,包括有用功能、性能水平和成本等。 在文章【质量管理】现代TRIZ中问题识别中的功能分析——相互接触分析-CSDN博客…

广告事件聚合系统设计

需求背景 广告事件需要进行统计,计费,分析等。所以我们需要由数据接入,数据处理,数据存储,数据查询等多个服务模块去支持我们的广告系统 规模上 10000 0000个点击(10000 00000 / 100k 1wQPS) …

C语言中,sizeof关键字(详细介绍)

目录 ‌1. 基本用法‌(1) ‌基本数据类型‌(2) ‌变量‌(3) ‌数组‌(4) ‌指针‌ ‌2. 特殊用法‌(1) ‌结构体与内存对齐‌(2) ‌动态内存分配‌(3) ‌表达式‌ ‌3. 注意事项‌‌1)sizeof 与 strlen 的区别‌:‌2)变长数组(VLA…

ADK 第三篇 Agents (LlmAgent)

Agents 在智能体开发套件(ADK)中,智能体(Agent)是一个独立的执行单元,旨在自主行动以实现特定目标。智能体能够执行任务、与用户交互、使用外部工具,并与其他智能体协同工作。 在ADK中&#x…

【深度学习】典型的 CNN 网络

目录 一、LeNet-5 (1)LeNet-5 网络概览 (2)网络结构详解 (3)关键组件与数学原理 3.1 局部感受野与卷积运算 3.2 权重共享 3.3 子采样(Pooling) 3.4 激活函数 (4…

4.8/Q1,中山大学用NHANES:膳食烟酸摄入量与非酒精性脂肪肝之间的关联

文章题目:Association between Dietary Niacin Intake and Nonalcoholic Fatty Liver Disease: NHANES 2003-2018 DOI:10.3390/nu15194128 中文标题:膳食烟酸摄入量与非酒精性脂肪肝之间的关联:NHANES 2003-2018 发表杂志&#xf…