Redis数据组织方式

前言

        Redis之所以高效,源自其优秀的架构设计。作为KV键值对存储数据库,数据的存储放在了内存中,KV键值对的组织方式更是其高效的原因之一。本文介绍其数据组织方式。

一、总体架构

        在使用Redis时,服务端接收多个客户端的命令进行处理,Redis的命令处理采用单线程模型。Redis在处理KV键值对时,在其内部维护了一个dictht。所有的键值对,无论value值的数据类型是String、List、Hash、Set、ZSet等,其都会使用一个抽象的通用结构dictEntry放在这张dictht中。通过对Key值hash操作,然后取余,就可以得到一个值该值对应dictht中的一个位置。通过此方式将其记录到dictht中。这样后续查询通过dictht组织的所有的键值对,当一个Key值收到后,通过对Key值进行hash,然后取余,该值就对应了dictht中的某个位置。这个位置具体记录了value值的相关信息,就可以获取到该信息。其中对于dictht的大小也需要一种机制来控制。假如dictht的长度为4,此时需要存储5个Key,那么必定会出现hash碰撞,即两个Key值的hash值取余后是一样的。dictht解决哈希碰撞的方式是拉链法,每一个hash槽位记录的并非一个dictEntry地址,而是一个dictEntry链表的地址。找到对应dictht中的槽位后可以通过遍历链表获取到具体的key值信息。如下图所示:

        相关数据结构如下所示:

typedef struct dictEntry {void *key;union {void *val;uint64_t u64;int64_t s64;double d;} v;struct dictEntry *next;
} dictEntry;
​
typedef struct dictht {dictEntry **table;unsigned long size;// 数组长度unsigned long sizemask; //size-1unsigned long used;//当前数组当中包含的元素
} dictht;
​
typedef struct dict {dictType *type;void *privdata;dictht ht[2];long rehashidx; /* rehash 标志位*/int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) 用于安全遍历*/
} dict;

二、dictht的扩容与缩容

        上述介绍了Redis的数据组织总体架构,即维护了dictht来维护所有的键值对,具体解决hash碰撞的方式为拉链法。这样就带来一个问题,当hash碰撞达到一定规模后,dictht中的链表就变得很长,此时dictht的查询效率就从O(1)退化到了O(n)。Redis对于该问题进一步通过对dictht扩容来解决。

        此处介绍一个hash冲突的概念:负载因子。负载因子 = used / size。 used为数组存储元素的个数,size为数组长度。

        负载因子可以反应hash冲突的程度,两者呈正比关系。Redis的负载因子上限为1。当Redis的负载因子 > 1时,会发生扩容。此时将dictht的长度扩容至原来的二倍。同时考虑数据的持久化操作,如果此时正在进行rdb、aof复写等持久化操作时,会阻止扩容。但是此时如果负载因子 > 5,则马上开始扩容。

        既然扩容是为了解决hash冲突的问题,及利用扩大空间来提升dictht的查询效率从而提高Redis的查询效率。那么当dictht达到一定长度时,如果利用率较低,此时就会造成资源的浪费。Redis对于此问题采用dictht缩容来解决。

        dictht的缩容也是根据负载因子,当负载因子 < 0.1 时,则会发生缩容。缩容的规则为缩减至恰好包含used的2的n次方。

三、渐进式rehash——合理解决扩容与缩容

        上述提到了dictht的扩容与缩容,这两个操作是在不同情况下调整dictht到一个合适状态。但是这个调整操作相对于Redis的命令处理而言是一个耗时操作。同时Redis的命令处理必须依赖dictht提供查询Key值的功能。如果直接地进行扩容或者缩容此时会阻塞一定时间命令处理。导致客户端短时间内无法响应。针对此问题Redis采取渐进式rehash操作,既保证了Redis客户端命令的及时处理,也保证了dictht的扩容与缩容能够及时进行。

        根据上述数据结构中dict的结构,可以看到其中ht变量,维护了两个dictht。这就是渐进式rehash的实现思路,Redis维护两个dictht,当需要进行rehash时,即需要进行扩容或者缩容时,Redis会将ht[0]中的元素重新经过hash函数生成64位整数,再对ht[1]的长度进行取余,从而映射到ht[1]中。

        而渐进式rehash中的渐进体现在:上述对Key值的重新映射不是一次性完成的,因为上文也阐述过一次性完成该工作会长期占用Redis,导致阻塞命令处理流程。Redis采用分治的思想,把整体的rehash工作分摊到客户端发来的每一条命令(Key的增删改查)中。即在rehash阶段,执行的每条命令都会对其中的Key值进行rehash操作,从而完成整个rehash工作。如果此时Redis处于空闲状态,那么Redis内部维护一个定时器,在定时器规定事件中最大执行1ms的rehash操作,每次rehash100个数组槽位。这样在Redis空闲状态也能一直推进rehash工作。

        对应两个ht的工作流程为:ht[0]:未发生rehash时,直接使用。rehash期间,存储了扩容和缩容前的数据。ht[1]:未发生rehash时,不会使用。rehash期间,其存储新的数据以及从ht[0]中迁移过来的数据。rehash工作完成后再将ht[0]指针直接指向ht[1]指向的数组,保证ht[0]永远指向正在使用的dictht。

 更多资料:0voice · GitHub

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

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

相关文章

java组件安全vulhub靶场

>1--XStream1.打开靶场cd vulhub-master/xstream/CVE-2021-29505 docker up -d2.下载反序列化工具https://github.com/frohoff/ysoserial可以使用clone命令进行下载&#xff0c;也可以直接下载jar文件3.使用以下命令来开启脚本&#xff0c;将是反弹shell的语句进行base64编码…

UCMT部分复现

复现结果&#xff1a;88.03272&#xff0c;误差在接受范围内 补充信息 作者未解决后续报错问题&#xff0c;不建议复现

IntelliJ IDEA 新手全方位使用指南

摘要本文面向刚接触软件开发、使用 IntelliJ IDEA 的新手&#xff0c;详细介绍了 IDEA 的背景、版本区别、核心功能、运行原理、界面操作、项目管理、运行配置、以及 Git 版本控制基础。文章突出实用操作和理解流程&#xff0c;帮助新手快速熟悉IDEA环境&#xff0c;顺利完成项…

Python如何将图片转换为PDF格式

引言 在日常工作和学习中&#xff0c;我们经常需要将多张图片合并成一个PDF文件&#xff0c;以便于分享或打印。Python提供了多种库来实现这一需求&#xff0c;本文将详细介绍三种常用的方法&#xff1a;img2pdf库、Pillow库和PyMuPDF库&#xff0c;并附上完整的代码示例。 方法…

Python如何合并两个Excel文件

引言 在日常数据处理中&#xff0c;合并Excel文件是常见需求。Python提供了多种库&#xff08;如pandas、openpyxl&#xff09;来实现这一操作。本文将详细介绍两种主流方法&#xff0c;并附上完整代码示例&#xff0c;帮助您高效完成Excel合并任务。 方法一&#xff1a;使用pa…

【SQL进阶】用EXPLAIN看透SQL执行计划:从“盲写“到“精准优化“

用EXPLAIN洞察SQL执行计划&#xff1a;从"盲目编写"到"精准优化" 很多开发者在编写SQL时仅凭直觉&#xff0c;直到查询超时才发现问题。MySQL内置的EXPLAIN工具能提前揭示查询执行逻辑&#xff0c;帮助预防性能隐患。本文将带你掌握EXPLAIN的核心用法&…

电影艺术好,电影知识得学

关于电影应该谈什么导演风格、演员技术、剧本结构、票房、政治因素等。一、纸上谈电影电影制作期&#xff1a;研发、前制、拍摄、后制、发行。一般成员只在某个时期出现。制片和导演会从头监督到尾。研发期&#xff1a; 剧本概念发想与成形的时期。创作自由度比较大&#xff0c…

FPGA学习笔记——简易的DDS信号发生器

目录 一、任务 二、分析 三、ROM IP核配置 四、Visio图 五、代码 &#xff08;1&#xff09;.v代码 &#xff08;2&#xff09;仿真代码 六、仿真 七、实验现象 一、任务 用串口模块&#xff0c;用上位机发送指令&#xff0c;FPGA接收&#xff0c;然后输出对应的波形&…

在NVIDIA Orin上用TensorRT对YOLO12进行多路加速并行推理时内存泄漏 (中)

接上篇 在NVIDIA Orin上用TensorRT对YOLO12进行多路加速并行推理时内存泄漏&#xff08;上&#xff09; 通过上篇的分析&#xff0c;发现问题在采集数据到传入GPU之前的阶段。但随着新一轮长时间测试发现&#xff0c;问题依然存在。 如上图&#xff0c;在运行20多分钟内存开始…

计数组合学7.17(Murnaghan–Nakayama 规则 )

7.17 Murnaghan–Nakayama 规则 我们已经成功地用基 mλm_\lambdamλ​、hλh_\lambdahλ​ 和 eλe_\lambdaeλ​ 表示了 Schur 函数 sλs_\lambdasλ​。本节我们将考虑幂和对称函数 pλp_\lambdapλ​。一个斜分划 λ/μ\lambda / \muλ/μ 是连通的&#xff0c;如果其分拆图…

使用 jlink 构建轻巧的自定义JRE

从 JDK 9 开始&#xff0c;Oracle JDK 和 OpenJDK 不再默认包含独立的 JRE 目录&#xff0c;而是提供了 jlink 工具&#xff08;Java 链接器&#xff09;&#xff0c;允许你根据需求自定义生成最小化的 JRE&#xff08;包含必要的模块&#xff09;。以下是使用 jlink 生成 JRE …

[IOMMU]面向芯片/SoC验证工程的IOMMU全景速览

面向芯片/SoC验证工程的IOMMU全景速览 摘要:面向芯片/SoC 验证工程的 IOMMU 全景速览:包含基础概念、主流架构要点(ARM SMMU、Intel VT‑d、RISC‑V IOMMU),Linux 软件栈关系,SoC 上的验证方法(功能、错误、性能、系统化流程和覆盖),以及一个可用的“通用 IOMM…

Jenkins全链路教程——Jenkins用户权限矩阵配置

在企业级CI/CD场景中&#xff0c;“权限混乱”往往比“构建失败”更致命——测试员误删生产流水线、实习生修改关键插件配置、多团队共用账号导致责任无法追溯……这些问题&#xff0c;99%都能用权限矩阵彻底解决&#xff01;今天&#xff0c;我们不仅会拆解权限矩阵的底层逻辑…

库函数蜂鸣器的使用(STC8)

使用库函数控制蜂鸣器&#xff08;STC8&#xff09; 在STC8系列单片机中&#xff0c;可以通过库函数或直接操作寄存器来控制蜂鸣器。以下是基于STC8库函数的常用方法&#xff1a; GPIO板蜂鸣器 #include "GPIO.h" #include "Delay.h"void GPIO_config()…

redis8.0.3部署于mac

macOS11因版本过低&#xff0c;安装redis时&#xff0c;Homebrew和源码编译两种方式都无法成功。将操作系统升级至macOS15再安装。Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据库&#xff0c;遵守 BSD 协议&#xff0c;它提供了一个高性能的键值…

【和春笋一起学C++】(三十三)名称空间的其他特性

目录 嵌套式名称空间 拓展——未命名的名称空间 嵌套式名称空间 示例代码1&#xff1a; namespace electronicEquipment {namespace computer{double price 4999.0;string modelNumber;string name;}namespace ElectronicWatch{double price 99.0;string modelNumber;stri…

异步电动机负载运行特性全解析

异步电动机负载运行特性详解 ——从空载到负载的完整分析一、为什么需要再谈“负载运行” 在上一篇《感应电动机空载特性深度剖析》中&#xff0c;我们已经看到&#xff1a;空载时&#xff0c;若定子加额定电压&#xff0c;转子转速 $n \approx n_s$&#xff08;同步转速&#…

使用 Ansys Discovery 进行动态设计和分析

Ansys Discovery 是一款多功能工具&#xff0c;为创建模型、探索仿真设计和分析解决方案提供了一个单一的交互式工作区。它允许用户使用直接建模技术创建和修改几何结构&#xff0c;定义仿真并与结果实时交互。Discovery 支持结构、流体流动、热和电磁设计&#xff0c;提供直观…

力扣热题100-----118.杨辉三角

案例 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1 输出: [[1]] 提示: 1 …

NTP /Chrony 网络时间协议

一、NTP&#xff08;network time protocol&#xff09;网络时间协议&#xff1a;实现时间同步&#xff0c;让设备时间与国际标准时间保持一致设备日志、服务日志需要记录时间分布式系统&#xff08;分布式数据库、分布式缓存、分布式储存、消息队列&#xff09;时间戳&#xf…