三、Redis五种常用数据结构-Hash

Hash是redis中常用的一种无序数据结构。结构类似HashMap。
具体结构如下:key field value

1、优缺点

1.1、优点

  • 同类数据归类整合储存,方便数据管理。
  • 相比于string操作消耗内存和CPU更小。
  • 分字段存储,节省网络流量。

1.2、缺点

  • 过期时间无法设置在field上,只能设置在key上
  • redis集群下不适合大规模使用

2、Hash底层结构

2.1、ziplist-压缩列表

2.1.1、使用条件
  • 哈希对象存储的键值对个数小于512个
  • 哈希对象存储的键值对的键和值的字符串长度小于64字节
2.1.2、数据结构

见list

2.1.3、ziplist的优点
  • 为什么不直接使用hashtable?

相比于hashtable,ziplist结构少了指针,减少了内存的使用。在redis中内存是非常珍贵的。

  • 为什么不使用linkedlist?

ziplist存储时内存地址分配是连续,查询更快。

2.2、dict-字典

字典是在hash存储的数据不满足ziplist中的两个任意一个条件时,使用的数据结构。
由于dict是一种常用的数据结构,但是c语言并不具备此种数据结构,因此redis开发人员自己设计和开发了redisdict结构。详细结构如下:

typedf struct dict{dictType *type;//类型特定函数,包括一些自定义函数,这些函数使得key和value能够存储void *private;//私有数据dictht ht[2];//两张hash表 int rehashidx;//rehash索引,字典没有进行rehash时,此值为-1unsigned long iterators; //正在迭代的迭代器数量
}dict;
  • typeprivate这两个属性是为了实现字典多态而设置额,当字典中存放着不同类型的值,对应的复制、比较函数也是不一样,这两个字段组合起来可以实现多态的方法调用。
  • ht[2],两个hash
  • rehashidx,辅助变量,用于记录rehash过程的进度,以及是否正在进行rehash等信息。当此值为-1时表示该dict没有进行rehash操作。
  • iterators,记录此时dict有几个迭代器正在进行遍历过程。
2.2.1、dictht-哈希表

dict结构上可以看出,dict实际上就是对dictht的操作,dictht的具体结构如下:

typedf struct dictht{dictEntry **table;//存储数据的数组 二维unsigned long size;//数组的大小unsigned long sizemask;//哈希表的大小的掩码,用于计算索引值,总是等于//size-1unsigned long used; 哈希表中中元素个数
}dictht;
  • table是一个dictEntry类型的数组,用户真正存储数据。
  • size表示**table这个数组的大小。
  • sizemask用于计算索引的位置,总是等于size-1
  • used表示**table数组中已有的节点个数。
2.2.2、dictEntry

上面分析dictht实际存储数据的是dictEntry数组,其结构定义如下:

typedf struct dictEntry{void *key;//键union{void val;unit64_t u64;int64_t s64;double d;}v;//值struct dictEntry *next;//指向下一个节点的指针
}dictEntry;

整个dict字典的结构示意图如下:
image.png

2.2.3、扩容与缩容

当哈希表的数量主键增大时,此时添加数据,产生hash冲突的概率主键增大,且dict也是采用拉链法解决hash冲突的,因此随着hash冲突的增加,链表的长度也在逐渐增大。这时查询的速度会随着链表的长度主键变慢。相反,当元素主键减少时,元素占用dict的空间逐渐减少,处于对内存的极致利用,此时就需要进行缩容操作。
dict的扩容和缩容操作有一点和Java中的HashMap结构类似,都有负载因子。负载因子一般用于表示集合当前被数据填充的程度。在Redis的字典dict中,负载因子=哈希表已存节点数量/哈希表长度,即:

load factor=ht[0].used/ht[0].size

Redis中,关于扩容和缩容有三条规则:

  • 没有执行BGSAVEBGREWRITEAOF指令的情况下,哈希表的负载因子大于等于1时进行扩容。
  • 正在执行BGSAVEBGREWRITEAOF指令的情况下,哈希表的负载因子大于等于5时进行扩容。
  • 负载因子小于0.1时,Redis自动对哈希表进行缩容操作。

Redis扩容和缩容的数量规则:

  • 扩容后:扩容后的dictEntry数组数量为第一个大于等于ht[0].used*22^n;
  • 缩容后:缩容后的dictEntry数组数量为第一个大于等于ht[0].used2^n;
2.2.4、rehash

Redis的扩容或者缩容,与Java中的HashMap类似都有rehash过程。Java中的HashMaprehash过程如下:

  1. 新建一个哈希表,一次性将当前的数据全部rehash,然后复制到新的哈希表上。
  2. 舍弃掉原来的哈希表,而持有新的hash表。这个过程是一个时间复杂度为O(n)的操作。

对于单线程的Redis而言很难承受这么高的时间复杂度的操作。因此Redisrehash操作相比较于HashMap有所不同。Redis采用渐进式rehash的方式。其过程如下:

  1. 假设当前数据在ht[0]上,那么首先会为ht[1]分配到足够的空间。如果是扩容ht[1]就按照扩容规则进行设置。如果是缩容ht[1]就按照缩容规则设置。
  2. dict结构中有个rehashidx字段,用来记录rehash的位置。**rehash=0,**表示rehash开始。
  3. rehash进行期间,每次对字典进行添加、删除、查找、更新操作时,除了执行指定的操作外,还会顺带将ht[0]哈希表上的数据rehashht[1]上,每rehash一个ht[0]上的数据到ht[1]rehashidx都会加1。每次顺带的rehash操作只会搬移少量的数据(100个元素)。
  4. 随着字典操作的不断进行,在某个时刻,ht[0]上的所有数据全部被rehashht[1]上,这时rehashidx的值为-1,表示rehash的操作已完成。

以上就是Redis中的dict渐进式rehash过程,但是这个过程存在两个问题:

  1. 在第三步说了,每次在对字典执行增删改查时才会触发rehash过程。万一某一时间段,一直都没有请求怎么办?

A:Redis中有一个定时器,会定时去判断rehash是否完成,如果没有完成,则继续进行rehash操作。

  1. rehash过程中维护两个hash表,是如何对外提供服务的?

A:对于添加操作,会将数据直接添加到ht[1]上,这样就会保证ht[0]上的数据只会减少不会增加。而对于**删除、更改、查询操作。**会直接在ht[0]上进行操作,尤其这三个操作都会涉及到查询,当在**ht[0]**上查询不到时,会接着去**ht[1]**上查找,如果在找不到,则表示此key不存在。

2.2.5、渐进式rehash的优缺点
  • 优点:采用分而治之的思想,将rehash操作分散到每一个对该哈希表的操作上以及定时函数上,避免了集中式的rehash带来的性能压力。
  • 缺点:在rehash期间内,需要保存两个hash表,对内存的占用稍大,而且如果在redis服务器内存满了的时候,突然进行**rehash**操作,会造成大量key被抛弃
2.2.6、思考题

为什么扩容时需要考虑BGSAVE的影响,而缩容时不需要?

  • BGSAVE时,dict进行扩容,则此时就需要为ht[1]分配内存,若是ht[1]的数据量很大时,就会占用更多的系统内存,造成内存页过多分离,所以为了避免系统耗费更多的开销去回收内存,此时最好不要进行扩容。
  • 缩容时,结合缩容的条件,此时负载因子<0.1,说明此时的dict中的数据很少,就算为ht[1]分配内存,也消耗不了多少资源。

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

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

相关文章

盘点一下近年来常用的电脑监控软件

企业电脑监控软件通常用于监视员工在工作时间内的电脑使用情况&#xff0c;以确保他们的工作效率和安全性。以下是几种常见的企业电脑监控软件&#xff1a; 1、Ping32 Ping32是一款集成多功能的企业级电脑监控软件&#xff0c;包括员工上网行为管理、文件外发审计、屏幕活动监…

Milvus Cloud 的RAG 的广泛应用及其独特优势

一个典型的 RAG 框架可以分为检索器(Retriever)和生成器(Generator)两块,检索过程包括为数据(如 Documents)做切分、嵌入向量(Embedding)、并构建索引(Chunks Vectors),再通过向量检索以召回相关结果,而生成过程则是利用基于检索结果(Context)增强的 Prompt 来激…

使用API有效率地管理Dynadot域名,设置所有域名默认whois信息

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

WordPress与Joomla有哪些差异

在前不久遇到Hostease的客户在咨询WordPress和Joomla要如何选择。他们之间有哪些区别。Hostease提供的虚拟主机都可以直接安装这2个网站程序。下面针对WordPress和Joomla进行一些分析和比较。 WordPress和Joomla都是流行的内容管理系统&#xff08;CMS&#xff09;&#xff0c;…

2024年51cto下载的视频怎么导出

如果你喜欢在51cto上观看各种专业技术视频&#xff0c;那么你可能想将喜欢的视频保存到本地设备中&#xff0c;以便随时随地观看。今天&#xff0c;我们就来探讨一下如何在2024年将51cto下载的视频导出到你的设备中 下载51cto的工具我已经打包好了&#xff0c;有需要的自己下载…

AI换脸原理(4)——人脸对齐(关键点检测)参考文献2DFAN:代码解析

注意,本文属于人脸关键点检测步骤的论文,虽然也在人脸对齐的范畴下。 1、介绍 在本文中,重点介绍了以下几项创新性的成果,旨在为人脸关键点检测领域带来新的突破。 首先,成功构建了一个卓越的2D人脸关键点检测基线模型。这一模型不仅集成了目前最优的关键点检测网络结构,…

信息熵为凹函数-推导

凹函数和凸函数&#xff0c;是凹凸是相对于x轴来说的&#xff0c;对于熵来说&#xff0c;它是凹函数。因为它是-log函数&#xff0c;函数曲线相对于x轴来说是凸的。 Jensen不等式推导 以下是证明熵是凹函数。 引理&#xff1a; ①Jensen不等式&#xff0c;条件&#xff1a;…

SpringBoot框架如何接入RocketMQ?

目录 一、SpringBoot框架介绍 二、RocketMQ介绍 三、RocketMQ的应用场景 四、SpringBoot框架如何接入RocketMQ 一、SpringBoot框架介绍 Spring Boot是一个开源的Java框架,它基于Spring框架,旨在简化Java应用程序的开发。Spring Boot通过自动化配置和约定优于配置的原则,大…

谷歌开源!用 js 编写 Shell 脚本! | 开源日报 No.247

google/zx Stars: 41.4k License: Apache-2.0 zx 是一个用于编写更好脚本的工具。 提供有用的包装器&#xff0c;简化了对 child_process 的操作转义参数并提供合理的默认值使用 JavaScript 编写复杂脚本时比 Bash 更方便可以直接使用 npm 安装 dani-garcia/vaultwarden St…

评估Transitions

Stateflow使用图表中的转换从一种OR状态移动到另一种OR状态。对于图表执行的输入和执行工作流,Stateflow评估转换以确定它们是否有效。有效转换是条件标签为true且路径以状态结束的转换。如果转换有效,则Stateflow将从源状态退出并进入目标状态。 评估Transitions的工作流 T…

图搜索算法 - 拓扑排序

相关文章&#xff1a; 数据结构–图的概念 图搜索算法 - 深度优先搜索法&#xff08;DFS&#xff09; 图搜索算法 - 广度优先搜索法&#xff08;BFS&#xff09; 拓扑排序 概念 几乎所有的工程都可分为若干个称作活动的子工程&#xff0c;而这些子工程之间&#xff0c;通常受…

Debug项目失败Run成功

一&#xff1a;问题 idea中启动服务&#xff0c;服务一直在启动中&#xff0c;最后超时启动失败 重新构建项目也是一样 二&#xff1a;个人分析 debug因为断点太多了项目起不起来&#xff0c;试一下run直接运行&#xff0c;项目可以快速启动 三&#xff1a;解决办法 在控制…

四、Redis五种常用数据类型-List

List是Redis中的列表&#xff0c;按照插入顺序保存数据&#xff0c;插入顺序是什么样的&#xff0c;数据就怎么保存。可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含232-1个元素(4294967295&#xff0c;每个列表超过40亿个元素)。是一种双向列表结构…

uniapp 如何修改 IPA 文件信息页的本地化语言

实现效果&#xff1a; 最终会对应到苹果商店的语言&#xff1a; 例如微信的语言就有多个&#xff1a; 操作&#xff1a; 在 mainfest.json 源码视图中加入&#xff1a; 具体对应的语言key值可以参考Xcode中的语言代码 这个取决于打包后的 lproj 文件 将后缀ipa改成zip打开即…

47. UE5 RPG 实现角色死亡效果

在上一篇文章中&#xff0c;我们实现了敌人受到攻击后会播放受击动画&#xff0c;并且还给角色设置了受击标签。并在角色受击时&#xff0c;在角色身上挂上受击标签&#xff0c;在c里&#xff0c;如果挂载了此标签&#xff0c;速度将降为0 。 受击有了&#xff0c;接下来我们将…

Linux中gitlab-runner部署使用备忘

环境&#xff1a; 操作系统:&#xff1a;CentOS8 gitlab版本&#xff1a;13.11.4 查看gitlab-runner版本 可以从https://packages.gitlab.com/app/runner/gitlab-runner/search找到与安装的gitlab版本相近的gitlab-runner版本以及安装命令等信息&#xff0c;我找到与13.11.4相…

C语言,实现数字谱到简谱的转换(二)

C语言&#xff0c;实现数字谱到简谱的转换&#xff08;二&#xff09; 前言&#xff1a;本文初编辑于2024年5月8日 CSDN&#xff1a;https://blog.csdn.net/rvdgdsva 博客园&#xff1a;https://www.cnblogs.com/hassle 前言 结合前文使用 之前的程序默认C调4/4拍&#xff…

windows11获取笔记本电脑电池健康报告

笔记本电脑的电池关系到我们外出时使用的安全&#xff0c;如果电池健康有问题需要及时更换&#xff0c;windows系统提供了检查电池健康度的方法。 1、打开命令行 1&#xff09;键入 winR 2&#xff09;键入 cmd 打开命令行。 2、在命令行运行如下指令&#xff0c;生成电池健…

美式期权和欧式期权区别的详细解析

美式期权和欧式期权的区别 美式期权和欧式期权是期权交易的两种主要形式&#xff0c;它们主要在行权时间、灵活性和价格等方面存在显著的区别。 文章来源/&#xff1a;股指研究院 美式期权的特点在于其买方可以在期权有效期内任何一天提出执行合约&#xff0c;即买方可以在到…

人工智能哪些大学比较好

人工智能领域的大学有很多&#xff0c;以下是一些国际上被广泛认可的一流大学&#xff1a; 1. **斯坦福大学&#xff08;Stanford University&#xff09;** - 位于美国加州的斯坦福大学拥有顶尖的人工智能研究中心&#xff0c;并在机器学习、自然语言处理等领域处于领先地位。…