Redis设计与实现——数据结构与对象

简单动态字符串(SDS)

SDS 的结构定义
  • len:记录当前字符串的实际长度(不包含 \0),获取长度的时间复杂度为 O(1)
  • free:记录未使用的空间大小,用于优化内存分配。
  • buf[]:实际存储字符的数组,末尾自动追加 \0(兼容 C 字符串函数)。
SDS 的核心特性
  • 预分配与惰性释放

    • 空间预分配:当 SDS 需要扩容时,Redis 会额外分配未使用空间(free)以减少内存重分配次数:

      若扩容后 len < 1MB:分配 len 的等量空间(总空间 = len + free + 1 = 2 * len + 1)。

      若扩容后 len ≥ 1MB:固定分配 1MB 未使用空间(总空间 = len + 1MB + 1)。

    • 惰性空间释放:当 SDS 缩短时,不立即回收内存,而是通过 free 记录剩余空间,供后续操作复用。

  • 二进制安全:SDS 的 buf 可以存储任意二进制数据(包括 \0),因为长度由 len 字段记录,而非依赖 \0 判断结束。

  • 兼容 C 字符串函数:SDS 的 buf 末尾自动追加 \0,可直接使用 <string.h> 中的函数(如 strcmp())。

  • 杜绝缓冲区溢出:所有修改操作(如拼接)前会检查剩余空间(free),不足时自动扩容。

链表

链表的定义与结构
  • 链表结点
    • 双向链接:每个节点包含指向前驱和后继的指针,支持双向遍历。
    • 值类型灵活value 字段为 void* 类型,可指向任意数据(字符串、整数、对象等)。
  • 链表对象(list
    • 头尾指针:直接访问头尾节点,使 LPUSHRPUSH 等操作时间复杂度为 O(1)
    • 长度字段len 直接记录节点数量,无需遍历即可获取长度(时间复杂度 O(1))。
    • 多态性支持:通过函数指针实现值的复制、释放和比较,支持不同类型数据的存储。
链表的特性
  • 双向无环链表

    • 双向:每个节点包含前驱和后继指针,支持双向遍历。

    • 无环:头节点的 prev 和尾节点的 next 均为 NULL,避免循环引用。

  • 高效的头尾操作

    • 头部插入/删除:直接通过 list->head 操作,时间复杂度 O(1)。

    • 尾部插入/删除:直接通过 list->tail 操作,时间复杂度 O(1)。

  • 多态性与类型安全

    • 存储任意数据:节点值通过 void* 指针存储,支持字符串、整数、对象等。

    • 自定义函数:通过 dupfreematch 函数实现类型相关的操作,例如:

      dup:深拷贝节点值(如复制一个 SDS 字符串)。

      free:释放节点值占用的内存(如销毁一个 Redis 对象)。

      match:比较节点值与给定值是否相等。

字典

字典的结构定义
  • 哈希表(dictht

    • size:哈希表的大小,初始为 4,每次扩容为当前大小的 2 倍。
    • sizemask:哈希掩码,用于计算键的索引(hash & sizemask)。
    • table:指向哈希桶数组的指针,每个桶是一个链表(链地址法)。
  • 哈希节点(dictEntry

    • key:指向键的指针(如 SDS 字符串)。
    • v:值的联合体,支持指针、整数、浮点数等类型。
    • next:指向冲突链中的下一个节点。
  • 字典对象(dict

    • ht[2]:两个哈希表,正常操作使用 ht[0],Rehash 时逐步迁移到 ht[1]
    • rehashidx:记录 Rehash 的进度(从 0 到 ht[0].size-1)。
    • type:指向 dictType 结构的指针,包含键和值的操作函数(如哈希函数、键比较函数)。
核心机制与算法
  • 哈希函数:Redis 默认使用 MurmurHash2 算法计算键的哈希值。

  • 键冲突解决

    • 链地址法:哈希冲突的节点通过链表连接,新节点插入链表的头部(时间复杂度 O(1))。

    • 负载因子load_factor = ht[0].used / ht[0].size,触发扩容的默认阈值是 load_factor ≥ 1(可配置)。

  • 渐进式 Rehash:当哈希表需要扩容或缩容时,Redis 通过渐进式 Rehash 避免一次性迁移所有数据导致的阻塞:

    • 准备阶段:为 ht[1] 分配新空间;设置 rehashidx = 0,表示 Rehash 开始。

    • 迁移阶段:Redis 迁移 ht[0].table[rehashidx] 的所有节点到 ht[1]rehashidx 递增,直到所有桶迁移完成。

    • 完成阶段:释放 ht[0],将 ht[1] 设置为 ht[0];重置 ht[1] 为空表,rehashidx = -1

跳跃表Skiplist

跳跃表的定义与结构
  • 跳跃表节点(zskiplistNode

    • ele:存储元素的唯一标识(如用户 ID),类型为 SDS 字符串。
    • score:排序分值(如用户的积分),支持浮点数。
    • backward:指向前驱节点,用于从尾到头遍历。
    • level[]forward——指向后继节点的指针;span——当前层到下一个节点的跨度,用于计算元素排名。
  • 跳跃表对象(zskiplist

    • header:头节点,包含所有可能的层级(默认 32 层),初始化时各层 forward 指向 NULL
    • tail:尾节点,支持快速逆序遍历。
    • length:记录元素数量,获取长度的时间复杂度为 O(1)。
    • level:记录当前跳跃表的最高层,决定查找路径的起始层。
跳跃表的核心特性
  • 多层链表结构

    • 层级随机生成:每个节点的层数在插入时随机确定(幂次定律:层数越高概率越低),确保高层级稀疏分布。

    • 查找路径优化:从最高层开始查找,逐步降层,跳过大量节点(类似二分查找)。

  • 排序与唯一性

    • 按分值排序:节点按 score 升序排列,相同 score 的节点按 ele 的字典序排列。

    • 成员唯一性ele 唯一,插入重复 ele 时直接更新 score

  • 范围查询支持

    • ZRANGE、ZRANK:利用 span 字段快速计算排名或遍历区间。

    • ZREVRANGE:通过 backward 指针逆序访问。

Redis 中的应用
  • 有序集合(Sorted Set)

    • 底层实现:当有序集合元素较多时,使用跳跃表(zset 结构包含跳跃表和字典,字典用于 O(1) 查找 ele 对应的 score)。

    • 典型命令ZADD——插入元素;ZRANGE——按排名范围获取元素;ZRANK——获取元素排名。

  • 集群节点管理:集群模式下,跳跃表用于维护槽(Slot)与节点的映射关系。

整数集合

整数集合的结构定义
  • encoding:编码方式,决定每个元素占用的字节数,INTSET_ENC_INT16INTSET_ENC_INT32INTSET_ENC_INT64
  • length:集合中元素的数量。
  • contents[]:元素的实际存储数组,元素按值从小到大排序,且无重复。
核心机制:动态升级
  • 触发条件:当插入一个无法用当前编码表示的整数时,整数集合自动升级编码。

  • 升级步骤

    • 计算新编码:根据插入值的大小选择最小兼容编码。
    • 扩容内存:重新分配空间,计算新编码下的总字节数(length * new_encoding_size)。
    • 数据迁移:从后向前依次将旧元素转换为新编码,避免覆盖问题。
    • 插入新元素:根据新元素的值插入到正确位置(保持有序性)。
    • 更新结构:修改 encoding 字段,完成升级。
Redis 中的应用
  • 集合键(Set Key):当集合元素全为整数且数量小于 set-max-intset-entries(默认512)时,Redis 使用整数集合。
  • 性能优化:小规模整数集合的内存效率远超哈希表(如存储 100个int16仅需 200 + 8 字节,而哈希表需至少 100个entry)。

压缩列表Ziplist

压缩列表的结构
  • 头部元数据

    • zlbytes(4字节):整个压缩列表占用的内存字节数。

    • zltail(4字节):尾节点(最后一个Entry)的偏移量(便于快速定位尾节点)。

    • zllen(2字节):节点数量(若值 ≤ 65535则为实际数量,否则需遍历计算)。

  • 节点(Entry)结构

    • prevlen:前驱节点的长度(字节数),用于逆向遍历。

    • encoding:当前节点的数据类型和长度编码。

    • content:实际存储的数据(整数或字节数组)。

  • 结束标记:0xFF标识压缩列表的结尾。

核心机制与操作
  • 编码方式

    • 整数编码:根据数值范围选择最小编码(如int16_tint24_tint32_tint64_t)。

    • 字符串编码:短字符串(长度 ≤ 63字节):encoding占1字节(2 + 6);长字符串:encoding占2或5字节,记录长度。

  • 连锁更新(Cascade Update)

    • 触发条件:插入或删除导致某个节点的prevlen从1字节扩展为5字节(或反之)。

    • 影响:可能引发后续多个节点的prevlen更新,最坏时间复杂度为 O(N^2)

    • 优化:实际场景中概率极低,Redis未做特殊处理。

Redis 中的应用
  • 列表键(List Key):当元素均为小整数或短字符串,且数量小于 list-max-ziplist-entries(默认512)时,使用压缩列表。
  • 哈希键(Hash Key):当字段和值均为小数据,且字段数小于 hash-max-ziplist-entries(默认512)时,使用压缩列表。
  • 有序集合(Zset):早期版本中,小规模有序集合使用压缩列表存储元素(分值相邻存储),现已被快速列表(Quicklist)替代。

对象

对象类型(type
类型常量对象类型底层数据结构示例命令
REDIS_STRING字符串对象SDS、整数、embstr 编码的 SDSSET, GET, INCR
REDIS_LIST列表对象压缩列表(Ziplist)、双向链表LPUSH, RPOP, LRANGE
REDIS_HASH哈希对象压缩列表、字典(Dict)HSET, HGET, HKEYS
REDIS_SET集合对象整数集合(Intset)、字典SADD, SMEMBERS
REDIS_ZSET有序集合对象压缩列表、跳跃表(SkipList)+ 字典ZADD, ZRANGE
编码方式(encoding
编码常量说明适用对象类型
REDIS_ENCODING_INT整数编码(long 类型)字符串对象
REDIS_ENCODING_EMBSTRembstr 编码的 SDS(短字符串)字符串对象
REDIS_ENCODING_RAWSDS 字符串(长字符串)字符串对象
REDIS_ENCODING_HT字典(哈希表)集合、哈希对象
REDIS_ENCODING_ZIPLIST压缩列表列表、哈希、有序集合对象
REDIS_ENCODING_INTSET整数集合集合对象
REDIS_ENCODING_SKIPLIST跳跃表 + 字典有序集合对象
REDIS_ENCODING_QUICKLIST快速列表(Redis 3.2+,链表+压缩列表)列表对象
REDIS_ENCODING_STREAM流(Stream,Redis 5.0+)流对象
对象的核心机制
  • 类型检查与命令多态

    • 类型检查:执行命令前,Redis 检查操作的键的值对象类型是否匹配。

    • 多态命令:同一命令对不同编码的对象执行不同操作。

  • 内存优化:动态编码转换

    对象类型初始编码转换条件转换后编码
    字符串对象EMBSTR字符串长度增加至 >44字节RAW(SDS)
    列表对象ZIPLIST元素数量 > list-max-ziplist-entries或元素长度 > list-max-ziplist-valueQUICKLIST
    哈希对象ZIPLIST字段数量 > hash-max-ziplist-entries或字段/值长度 > hash-max-ziplist-valueHT(字典)
    集合对象INTSET插入非整数元素或元素数量 > set-max-intset-entries(默认512)HT(字典)
    有序集合对象ZIPLIST元素数量 > zset-max-ziplist-entries或元素长度 > zset-max-ziplist-valueSKIPLIST + 字典
  • 内存管理:引用计数与共享对象

    • 引用计数(refcount

      对象被创建时 refcount=1

      对象被引用时 refcount++(如被加入数据库、被客户端缓存)。

      对象被解除引用时 refcount--,当 refcount=0 时释放内存。

  • 共享对象:Redis 预先创建 0~9999 的整数对象供全局共享,减少重复创建。

  • 空转时间(lru)与淘汰策略

    • LRU 模式lru 字段记录对象最后一次被访问的时间戳(精度为秒),用于 volatile-lruallkeys-lru 淘汰策略。

    • LFU 模式lru 字段分为两部分(高 16 位分钟级时间戳,低 8 位访问频率),用于 volatile-lfuallkeys-lfu

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

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

相关文章

NeurIPS 2025 截稿攻略

会议资讯 NeurIPS&#xff0c;全称神经信息处理系统大会&#xff0c;是一个关于机器学习和计算神经科学的国际会议。NeurIPS是CCF&#xff08;计算机学会&#xff09;推荐的A类会议&#xff01;是机器学习领域内最具难度、水平最高且影响力最强的会议之一。它与ICML&#xff0…

Java中堆栈

文章目录 Java中堆栈1. 栈&#xff08;Stack&#xff09;特点示例 2. 堆&#xff08;Heap&#xff09;特点示例 3. 核心区别4. 常见问题5. 内存可视化示例内存布局示意图&#xff1a; 总结 Java中堆栈 在 Java 中&#xff0c;“堆栈” 通常指的是堆&#xff08;Heap&#xff0…

【类拷贝文件的运用】

常用示例 当我们面临将文本文件分成最大大小块的时&#xff0c;我们可能会尝试编写如下代码: public class TestSplit {private static final long maxFileSizeBytes 10 * 1024 * 1024; // 默认10MBpublic void split(Path inputFile, Path outputDir) throws IOException {…

打破产品思维--被讨厌的勇气--实战5

课程&#xff1a;B站大学 记录产品经理实战项目系统性学习&#xff0c;从产品思维&#xff0c;用户画像&#xff0c;用户体验&#xff0c;增长数据驱动等不同方向理解产品&#xff0c;从0到1去理解产品从需求到落地的全过程&#xff0c;测试左移方向&#xff08;靠近需求、设计…

【Autosar SecOC 1.信息安全原理介绍】

这里写目录标题 1 背景2 了解黑客攻击原理3 SecOC实现数据的真实性与完整性校验3.1 数据身份验证完成真实性验证3.2 防止重放攻击 1 背景 在今天的车载网络中&#xff0c;大部分数据传输是在没有任何特殊安全措施的情况下进行的。因此&#xff0c;一旦能够直接访问车辆的总线&a…

基于SpringBoot的校园周边美食探索及分享平台【附源码+数据库+文档下载】

一、项目简介 本项目是一个基于 SpringBoot Vue 的校园周边美食探索与分享平台&#xff0c;专为在校大学生开发&#xff0c;集美食推荐、好友互动、收藏分享于一体。 通过平台&#xff0c;用户可以探索学校周边的美食店铺、发布美食鉴赏、添加好友进行交流分享。同时&#x…

无偿帮写毕业论文

以下教程教你如何利用相关网站和AI免费帮你写一个毕业论文。毕竟毕业论文只要过就行&#xff0c;脱产学习这么多年&#xff0c;终于熬出头了&#xff0c;完成毕设后有空就去多看看亲人好友&#xff0c;祝好&#xff01; 一、找一个论文模板(最好是overleaf) 废话不多说&#…

15 个 Azure DevOps 场景化面试问题及解答

问题 1. 解释 Azure DevOps YAML 管道的典型结构。 您可以从管道的整体结构开始&#xff0c;从触发器开始。您也可以选择解释它可能包含的不同类型的阶段&#xff1a;构建、测试、扫描、部署等。 Azure DevOps YAML 管道结构示例 触发器指示管道运行。它可以是持续集成 (CI) 或…

Java 大视界 -- Java 大数据机器学习模型在元宇宙虚拟场景智能交互中的关键技术(239)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

本地不安装oracle,还想连oracle

1.首先要用navicat,或者toad打开连接数据库 2.安装oracle客户端&#xff0c;有时候OCI.dll需要看数据库版本&#xff0c;我们Oracle数据库是12C&#xff0c;可以用这个版本 3. 4.配置环境变量 变量名&#xff1a;NLS_LANG变量值&#xff1a;SIMPLIFIED CHINESE_CHINA.ZHS16GBK …

LabVIEW车牌自动识别系统

在智能交通快速发展的时代&#xff0c;车牌自动识别系统成为提升交通管理效率的关键技术。本案例详细介绍了基于 LabVIEW 平台&#xff0c;搭配大恒品牌相机构建的车牌自动识别系统&#xff0c;该系统在多个场景中发挥着重要作用&#xff0c;为交通管理提供了高效、精准的解决方…

deque底层数据结构以及和queue的异同

文章目录 底层数据结构原理关键组成部分操作效率与其他容器的对比适用场景C STL中的实现细节总结 deque和queue的异同相同点不同点 deque&#xff08;双端队列&#xff09;是一种具有高效两端插入和删除操作的数据结构&#xff0c;常见于C标准库&#xff08;STL&#xff09;和其…

WordPress 网站上的 jpg、png 和 WebP 图片插件

核心功能 1. 转换 AVIF 并压缩 AVIF 将您 WordPress 网站上的 jpg、png 和 WebP 图片转换为 AVIF 格式&#xff0c;并根据您设置的压缩级别压缩 AVIF 图片。如果原始图片已经是 WordPress 6.5 以上支持的 AVIF 格式&#xff0c;则原始 AVIF 图片将仅被压缩。 2. 转换 WebP 并…

Docker Volumes

Docker Volumes 是 Docker 提供的一种机制&#xff0c;用于持久化存储容器数据。与容器的生命周期不同&#xff0c;Volumes 可以独立存在&#xff0c;即使容器被删除&#xff0c;数据仍然保留。以下是关于 Docker Volumes 的详细说明&#xff1a; 1. 为什么需要 Volumes&#…

西电 | 2025年拟录取研究生个人档案录取通知书邮寄通知

各位考生&#xff1a; 我校2025年硕士研究生录取工作已结束&#xff0c;根据相关工作管理规定&#xff0c;现将个人档案转调及录取通知书邮寄信息确认等有关事宜通知如下&#xff1a; 一、个人档案转调 &#xff08;邮寄档案请务必使用EMS&#xff09; 1.全日制考生 录取类…

ExcelJS库的使用

ExcelJS 安装 npm install exceljs新的功能! Merged fix: styles rendering in case when “numFmt” is present in conditional formatting rules (resolves #1814) #1815. Many thanks to andreykrupskii for this contribution!Merged inlineStr cell type support #15…

时空注意力机制深度解析:理论、技术与应用全景

时空注意力机制作为深度学习领域的关键技术&#xff0c;通过捕捉数据在时间和空间维度上的依赖关系&#xff0c;显著提升了时序数据处理和时空建模能力。本文从理论起源、数学建模、网络架构、工程实现到行业应用&#xff0c;系统拆解时空注意力机制的核心原理&#xff0c;涵盖…

wxWidgets 3.2.8 发布,修复了GTK下,wxStaticText显示文本异常的问题

详细如下&#xff1a; 3.2.8 是稳定的 3.2 系列中的最新维护版本&#xff0c;现已在 GitHub 上提供&#xff0c;您可以从中下载带有 所选 Windows 的库源和文档以及二进制文件 编译器&#xff0c;例如 Microsoft Visual C、MinGW-w64 和 TDM-GCC。您还可以阅读更新的文档 版本&…

网页Web端无人机直播RTSP视频流,无需服务器转码,延迟300毫秒

随着无人机技术的飞速发展&#xff0c;全球无人机直播应用市场也快速扩张&#xff0c;从农业植保巡检到应急救援指挥&#xff0c;从大型活动直播到智慧城市安防&#xff0c;实时视频传输已成为刚需。预计到2025年&#xff0c;全球将有超过1000万架商用无人机搭载直播功能&#…

思维链框架:LLMChain,OpenAI,PromptTemplate

什么是思维链,怎么实现 目录 什么是思维链,怎么实现思维链(Chain of Thought)在代码中的实现方式1. 手动构建思维链提示2. 少样本思维链提示3. 自动思维链生成4. 思维链与工具使用结合5. 使用现有思维链框架:LLMChain,OpenAI,PromptTemplate思维链实现的关键要点思维链(C…