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

news2025/1/4 7:23:29

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时,此值为-1
    unsigned 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-1
    unsigned 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://www.coloradmin.cn/o/1653256.html

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

相关文章

基于边缘智能网关的工业燃气管网监测应用

随着城市化和工业化的飞速发展&#xff0c;燃气的使用量和应用范围持续增加&#xff0c;燃气管网作为承载燃气输送的设施&#xff0c;安全问题至关重要。一旦燃气管网发生泄漏事故&#xff0c;极易引发起火、爆炸等&#xff0c;从而酿成人员伤亡及财产损失的恶性事故。 得益于物…

VMware 虚拟机自定义规范 - 更优雅的虚拟机开局

介绍 虚拟机自定义规范可以在你克隆虚拟机的时候在vCenter 的Web界面设定虚拟机的主机名、单/多网卡IP的IP和网关、DNS服务器、唯一标识符重置&#xff08;SID等&#xff09;、硬盘分区自动扩容、设定密码、密钥、时区等信息。 让管理员不需要进入虚拟机系统内部进行配置&…

运用远期交易防范外汇风险

随着全球化的深入&#xff0c;跨境贸易和投资愈加频繁&#xff0c;外汇风险成为各类企业和投资者必须面对的现实问题。汇率的波动可能导致交易和投资的成本大幅增加&#xff0c;甚至引发利润损失。在这种情况下&#xff0c;远期交易作为一种有效的外汇风险对冲工具&#xff0c;…

Springboot整合飞书向群组/指定个人发送消息/飞书登录

Springboot整合飞书向群组发送消息 飞书开放平台创建企业自建应用 添加应用能力-机器人 创建完成后&#xff0c;进入应用详情页&#xff0c;可以在首页看到 App Id 和 App Secret 在飞书pc端创建一群机器人 此处可以拿到该机器人的webhook地址,通过https的方式,也可以调用发送…

人大金仓报The connection attempt failed.Reason:Connection reset解决办法

在连接人大京仓数据库 的时候报下面的错误 解决办法&#xff1a; 更换这里的IP地址就行&#xff0c;不要用127.0.0.1&#xff0c;然后就可以了

Android单行字符串末尾省略号加icon,图标可点击

如图 设置仅显示单行字符串&#xff0c;末尾用省略号&#xff0c;加跟一个icon&#xff0c;icon可点击 tvName.text "test"val drawable ResourcesCompat.getDrawable(resources, R.mipmap.icon_edit, null)tvName.setCompoundDrawablesWithIntrinsicBounds(null,…

华为认证HCIE考试过程的小细节|备考注意事项

大家好&#xff0c;我是来自武汉软件工程职业学院计算机网络专业的李同学&#xff0c;我在2024年1月3日通过了华为Datacom-HCIE认证&#xff0c;在此把我的一些考证心得分享给正在备考的同学们。 感谢讯方的老师们 我能通过HCIE考试&#xff0c;离不开各位讯方老师的教导。感…

碳课堂|如何开展碳排放核算? ISO 14064-2 项目层次要点解读

为提高企业组织碳排放报告信誉度&#xff0c;国际标准化组织&#xff08;ISO&#xff09;发布了ISO14064标准&#xff0c;其中《ISO 14064-2 项目层次上对温室气体减排和清除增加的量化、监测和报告的规范及指南》提供了项目策划阶段的原则要求&#xff0c;以及项目实施阶段的量…

Jmeter性能测试(五)

一、Jmeter参数化常用方式 1、CSV 数据文件设置 2、查询数据库(JDBC Connection Configuration) 二、CSV 数据文件设置 1、准备一个txt文件(不需要写表头&#xff0c;直接写你要用的数据就行了&#xff0c;多个字段用英文逗号隔开) 2、添加一个CSV 数据文件设置(放全局最上…

PyQt5批量生成Checkbox及批量检查Checkbox的勾选状态

批量生成Checkbox并添加到TableWidget中 for i in range(10):checkbox_i QCheckBox(fCheckbox_{i}) # 生成Checkbox并命名为Checkbox_iself.ui_1.tableWidget_1.setCellWidget(i,1,checkbox_i) 批量检查勾选状态 # 批量生成Checkbox并存入列表 list_Checkbox_1 [] for …

工程伦理课堂记录

文章目录 0. 导论0.1 工程伦理教育的意义0.2 工程伦理教育要实现的目标 1. 工程与伦理1.1 工程伦理学科的产生1.2 工程和技术1.3 工程概念的理解演进1.4 工程的过程1.5 工程的特点1.6 工程活动的七个维度总结 2. 伦理2.1 道德伦理的概念2.2 道德伦理的关系2.3 伦理规范2.4 伦理…

Vue3---router(安装、路由跳转、路由守卫、本地存储)

Vue3—router&#xff08;安装、路由跳转、路由守卫、本地存储&#xff09; 目录 Vue3---router&#xff08;安装、路由跳转、路由守卫、本地存储&#xff09;基础使用安装创建路由 路由跳转无参跳转js写法html写法 有参跳转queryparams 路由守卫额外&#xff1a;本地存储sessi…

旧衣回收小程序开发:线上回收模式成为行业发展趋势

当下人们生活水平在不断提高&#xff0c;对衣服的要求也在增加&#xff0c;更新速度越来越快&#xff0c;闲置下来的旧衣服也在增加&#xff0c;为了减少浪费&#xff0c;旧衣回收行业受到了大众的关注。旧衣回收对我国资源回收、环境保护具有非常大的意义。 在互联网时代下&a…

练英语口语的app哪个好?6个软件教你快速练习英语口语

练英语口语的app哪个好&#xff1f;6个软件教你快速练习英语口语 练习英语口语对于提高语言能力非常重要&#xff0c;而现代科技为我们提供了许多方便实用的应用来帮助我们快速有效地进行口语练习。以下是六款优质的英语口语练习应用&#xff0c;它们结合了各种学习方式和技术…

数据库系统理论——关系数据库

文章目录 一、关系&#xff08;数据结构&#xff09;1、概述2、名词解释3、关系模式、关系数据库、关系数据库模式4、基本关系的性质 二、关系操作&#xff08;数据操作&#xff09;三、关系的完整性1、实体完整性2 、参照完整性3、用户自定义的完整性 四、关系代数五、习题 前…

解决Redis的键值前出现类似\xAC\xED\x00\x05t\x00*这样的字符序列

文章目录 1.问题2.解决方法3.StringRedisTemplate和RedisTemplate的区别 1.问题 在使用RedisTemplate对Redis进行操作时,发现Reids键值对前有\xAC\xED\x00\x05t\x00*这样的字符序列 如图所示: 虽说不影响使用,但是听影响观感的 2.解决方法 查找了很多方法,可以指定RedisTem…

笔试强训Day20 动态规划 模拟

经此一役小红所向无敌 题目链接&#xff1a;A-经此一役小红所向无敌_牛客小白月赛37 (nowcoder.com) 思路&#xff1a; 水题 直接跟思路即可。 AC code&#xff1a; #include<iostream> using namespace std; typedef long long LL; LL a1,a2,b1,b2,t1,t2,sum; int m…

Observability:监控与可观察性不同的 3 个原因

作者&#xff1a;来自 Elastic Elastic Observability Team 监控和可观察性通常可以互换使用&#xff0c;但它们并不完全相同。 监控是可观察性的重要组成部分&#xff0c;但可观察性远远超出了传统监控实践的范围。 主要区别&#xff1a;监控从各个组件收集数据 —— 时间和内…

高阶RAG-ReRank

1.背景-现RAG存在的问题 现在很明显&#xff0c;仅仅依靠向量检索技术不足以开发 RAG 应用程序&#xff0c;尤其是在生产环境中部署。 以下为案例&#xff1a; 关键词搜索容易返回不回答问题的结果稠密检索容易返回不正确的结果 实际RAG检索中也有很多类型问题&#xff0c;…

stm32 st7735驱动 详解

初始化指令 void LCD_Init(void) { #if USE_SIM_SPILCD_SIM_SPI_GPIO_Init(); #endifLCD_RES_0();//复位HAL_Delay(100);LCD_RES_1();HAL_Delay(100);LCD_BLK_1();//打开背光HAL_Delay(100);//************* Start Initial Sequence **********//LCD_SPI_Send_Cmd(0x11); //Sl…