当前位置: 首页 > news >正文

Redis遇到Hash冲突怎么办?

这是小伙伴之前遇到的一个面试题,感觉也是一个经典八股,和大伙分享下。

一 什么是 Hash 冲突

Hash 冲突,也称为 Hash 碰撞,是指不同的关键字通过 Hash 函数计算得到了相同的 Hash 地址。

Hash 冲突在 Hash 表中是不可避免的,因为 Hash 表的地址空间有限,而可能的关键字数量是无限的。

为了解决 Hash 冲突,有几种常见的方法:

  1. 链地址法(Chaining):这是最常用的方法之一,每个 Hash 表的桶(bucket)都维护一个链表,所有散列到同一个位置的元素都存储在这个链表中。当发生冲突时,新元素被添加到该链表的末尾。这种方法的优点是操作简单,插入、查找和删除的时间复杂度为 O(1),但当链表长度较长时,查找效率会降低,并且需要额外的内存空间来存储链表结构。

  2. 开放寻址法(Open Addressing):这种方法也称为闭散列,当发生 Hash 冲突时,会顺序地查找下一个可用的数组位置,直到找到一个空闲位置为止。开放寻址法有几种变体,包括线性探测、二次探测和伪随机探测。线性探测法是最简单的形式,它按顺序检查下一个空闲位置。二次探测法在发生冲突时,在表的左右进行跳跃式探测。伪随机探测法则使用伪随机数序列来确定下一个探查位置。

  3. 再 Hash 法(Rehashing):这种方法同时构造多个不同的 Hash 函数,当发生冲突时,使用第二个 Hash 函数计算地址,直到找到一个不发生冲突的位置。这种方法不易产生聚集,但增加了计算时间。

  4. 建立公共溢出区:将 Hash 表分为基本表和溢出表,将发生冲突的元素都存放在溢出表中。这种方法可以减少冲突,但需要额外的存储空间。

不同的编程语言在面临这个问题时也都采取了不同策略,例如:

  • Python 采用开放寻址。字典 dict 使用伪随机数进行探测。
  • Java 采用链式地址。自 JDK1.8 以来,当 HashMap 内数组长度达到 64 且链表长度达到 8 时,链表会转换为红黑树以提升查找性能。
  • Go 采用链式地址。Go 规定每个桶最多存储 8 个键值对,超出容量则连接一个溢出桶;当溢出桶过多时,会执行一次特殊的等量扩容操作,以确保性能。

小伙伴们需要先熟悉这些解决方案,因为 Redis 中的解决方案无外乎就是这四种方案中的某几种。

二 Redis 中的 Hash

Redis 中的 Hash 数据结构在底层使用了两种不同的数据结构来存储键值对:

  1. 压缩列表(ziplist):当 Hash 表中的元素数量较少,并且每个元素的值都小于特定阈值(例如,值的长度小于 64 字节)时,Redis 会使用压缩列表来存储 Hash 表。压缩列表是一种内存高效的数据结构,它将所有的元素存储在一块连续的内存空间中,这样可以减少内存碎片和内存分配次数。但是,当元素数量增加或者单个元素的大小超过阈值时,压缩列表的性能会下降,因为它需要频繁地进行内存重新分配和数据复制。

  2. Hash 表(hash table):当 Hash 表中的元素数量较多,或者元素的大小超过压缩列表的阈值时,Redis 会使用一个普通的 Hash 表来存储数据。这个 Hash 表由数组和链表组成,每个数组的索引位置上可以存储多个元素,这些元素通过链表连接起来。当 Hash 表中的元素数量增加到一定程度时,Redis 会进行 rehash 操作,即创建一个新的更大的 Hash 表,并将旧表中的所有元素重新映射到新表中

Redis 会根据 Hash 表的大小和元素的数量自动在这两种数据结构之间进行切换,以保证性能和内存效率。这种动态的数据结构选择机制使得 Redis 的 Hash 数据结构既灵活又高效。

从上面的介绍中小伙伴们其实能看到,Redis 在处理 Hash 冲突的时候,用到了两种不同的方案:

  • 链地址法
  • rehash

三 Redis 如何解决 Hash 冲突

根据前面的介绍,小伙伴们已经明白了 Redis 在处理 Hash 冲突的时候,用到了两种不同的方案:链地址法和 rehash。

第一种链地址法大家应该是比较熟悉的,我们 Java 里边早期的 HashMap 就是这样的,具体数据结构如下图:

不过链地址法有一个弊端,就是如果出现大量的 key 冲突导致链表过长,此种情况下会导致数据的检索效率变慢,这不符合 Redis 高性能的人设,那怎么办呢?

为了保持高效,Redis 会对 Hash 表做 rehash 操作,也就通过增加 Hash 桶来减少冲突。为了 rehash 更高效,Redis 还默认使用了两个全局 Hash 表,一个用于当前使用,称为主 Hash 表,一个用于扩容,称为备用 Hash 表。

具体来说,在 Hash 表扩容时,Redis 首先会创建一个新的 Hash 表,该 Hash 表的大小是原有 Hash 表的两倍,然后将原有 Hash 表中的键值对逐一迁移到新的 Hash 表中。

在迁移过程中,Redis 会为每个被迁移的键值对计算出其在新 Hash 表中的位置,并将其插入到相应的位置上。在迁移完成后,Redis 会将新 Hash 表作为当前 Hash 表,用于存储新的键值对,同时释放旧 Hash 表的内存。

由于迁移过程是逐步进行的,因此在迁移过程中,既可以对新 Hash 表进行写入操作,也可以对旧 Hash 表进行读取操作,从而保证了 Redis 服务的正常运行。

四 小结

Redis 通过链地址法解决 Hash 冲突,并通过渐进式 rehash 保持 Hash 表的性能。

链地址法实现简单且在负载因子较低时性能较好,但在负载因子较高时性能会下降。渐进式 rehash 通过分批次迁移数据,避免了 rehash 过程中的服务阻塞,从而保持了系统的高性能和高可用性。

通过以上机制,Redis 在处理 Hash 冲突时能够有效地平衡性能和复杂度,确保在各种使用场景下都能提供高效的数据存储和检索服务。

相关文章:

Redis遇到Hash冲突怎么办?

这是小伙伴之前遇到的一个面试题,感觉也是一个经典八股,和大伙分享下。 一 什么是 Hash 冲突 Hash 冲突,也称为 Hash 碰撞,是指不同的关键字通过 Hash 函数计算得到了相同的 Hash 地址。 Hash 冲突在 Hash 表中是不可避免的&am…...

React综合指南(四)

61、描述React事件处理。 为了解决跨浏览器兼容性问题,React中的事件处理程序将传递SyntheticEvent实例,该实例是React跨浏览器本机事件的跨浏览器包装器。这些综合事件具有与您惯用的本机事件相同的界面,除了它们在所有浏览器中的工作方式相…...

Spring集成Redisson及存取几种基本类型数据

目录 一.什么是Redisson 二.为什么要使用Redisson 三.Spring集成Redisson 1.添加依赖 2.添加配置信息 3.添加redisson配置类 四.Redisson存取各种类型数据 1.字符串(String类型) 存储 获取 2.object对象类型 1.实体类信息 2.存储 3.获取 3.List集合类型 第一种…...

Maplibre-gl\Mapbox-gl改造支持对矢量瓦片加密

Maplibre-gl是Mapbox-gl剔除自带地图服务之后的一个分支,代码很相似。Maplibre-gl\Mapbox-gl使用的pbf格式的矢量瓦片,数据量小,渲染效果好。但也存在着信息泄露的风险。但如果想使用这个开发框架的前端渲染效果,还必须要使用这个格式。最近研究了一下如何对矢量瓦片进行加…...

【功能安全】技术安全概念TSC

目录 01 TSC定义 02 TSC注意事项 03 TSC案例 📖 推荐阅读 01 TSC定义 所处位置 TSC:Technical safety concept技术安全概念 TSR:Technical safety requirement技术安全需求 在系统开发阶段属于安全活动4-6 系统层产品开发示例 TSC目的...

Spark数据源的读取与写入、自定义函数

1. 数据源的读取与写入 1.1 数据读取 读文件 read.jsonread.csv csv文件由两个部分组成:头部数据(也就是字段数据)、行数据。 read.orc 读数据库 read.jdbc(jdbc连接地址,table‘表名’,properties{‘user’用户名,‘password’密码,‘driv…...

LeetCode 每日一题 2024/10/14-2024/10/20

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 10/14 887. 鸡蛋掉落10/15 3200. 三角形的最大高度10/16 3194. 最小元素和最大元素的最小平均值10/17 3193. 统计逆序对的数目10/18 3191. 使二进制数组全部等于 1 的最少操…...

接口测试(六)jmeter——参数化(配置元件 --> 用户定义的变量)

一、jmeter——参数化(配置元件 --> 用户定义的变量) 注:示例仅供参考 1. 参数化格式:${变量名} 2. 配置元件:用户定义的变量 3. 添加【用户定义的变量】,【线程组】–>【添加】–>【配置元件】–…...

【学习笔记】网络流

背景 马上ICPC了&#xff0c;很惊奇的发现自己没整理网络流的板子。 最大流 dinic 这里选用的是二分图最大匹配的板子&#xff1a;飞行员配对方案问题 #include<bits/stdc.h> #define int long long using namespace std; const int N1e67,inf1e18; struct E {int to…...

【鸡翅Club】项目启动

一、项目背景 这是一个 C端的社区项目&#xff0c;有博客、交流&#xff0c;面试学习&#xff0c;练题等模块。 项目的背景主要是我们想要通过面试题的分类&#xff0c;难度&#xff0c;打标&#xff0c;来评估员工的技术能力。同时在我们公司招聘季的时候&#xff0c;极大的…...

python+大数据+基于热门视频的数据分析研究【内含源码+文档+部署教程】

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…...

【电子电力】基于PMU相量测量单元的电力系统状态评估

摘要 相量测量单元&#xff08;PMU&#xff09;作为一种精确且快速的实时监控设备&#xff0c;在电力系统状态评估中发挥了重要作用。本文研究了在没有PMU和部署PMU情况下&#xff0c;电力系统的电压角度和电压幅值估计误差的差异。通过比较实验结果&#xff0c;发现PMU的应用…...

ubuntu修改默认开机模式(图形/终端)

将 Ubuntu 16 系统设置为开机进入终端模式&#xff1a; 打开终端。编辑 Grub 配置文件&#xff1a;sudo nano /etc/default/grub。找到 GRUB_CMDLINE_LINUX_DEFAULT 行&#xff0c;将其修改为 GRUB_CMDLINE_LINUX_DEFAULT"text"。保存并退出编辑器&#xff08;Ctrl …...

LaMI-DETR:基于GPT丰富优化的开放词汇目标检测 | ECCV‘24

现有的方法通过利用视觉-语言模型&#xff08;VLMs&#xff09;&#xff08;如CLIP&#xff09;强大的开放词汇识别能力来增强开放词汇目标检测&#xff0c;然而出现了两个主要挑战&#xff1a;&#xff08;1&#xff09;概念表示不足&#xff0c;CLIP文本空间中的类别名称缺乏…...

AI大模型是否有助于攻克重大疾病?

AI大模型在攻克重大疾病方面展现出了巨大的潜力&#xff0c;特别是在疾病预测、药物研发、个性化医疗等领域有着广泛应用。具体来说&#xff0c;AI大模型能够帮助以下几方面&#xff1a; 1、疾病预测与诊断&#xff1a;AI大模型通过分析海量的医学数据&#xff0c;可以提高重大…...

【渗透测试】-红日靶场-获取web服务器权限

拓扑图&#xff1a; 前置环境配置&#xff1a; Win 7 默认密码&#xff1a;hongrisec201 内网ip:192.168.52.143 打开虚拟网络编辑器 添加网络->VMent1->仅主机模式->子网ip:192.168.145.0 添加网卡&#xff1a; 虚拟机->设置-> 添加->网络适配器 保存&a…...

python 深度学习 项目调试 图像分割 segment-anything

起因&#xff0c; 目的: 项目来源: https://github.com/facebookresearch/segment-anything项目目的: 图像分割。 提前图片中的某个目标。facebook 出品&#xff0c; 居然有 47.3k star! 思考一些问题 我可以用这个项目来做什么?给一个图片&#xff0c; 进行分割&#xff0…...

【GO实战课】第六讲:电子商务网站(6):支付和订单处理

1. 简介 本课程将探讨电子商务网站的支付和订单处理功能,以及使用GO语言实现。在本课程中,我们将介绍如何设计一个可扩展、可靠和高性能的支付和订单处理系统,并演示如何使用GO语言编写相关代码。 本课程的目标是帮助学生理解电子商务网站的支付和订单处理功能,并提供一个…...

专题十三_记忆化搜索_算法专题详细总结

目录 1. 斐波那契数&#xff08;easy&#xff09; 那么这里就画出它的决策树 &#xff1a; 解法一&#xff1a;递归暴搜 解法二&#xff1a;记忆化搜索 解法三&#xff1a;动态规划 1.暴力解法&#xff08;暴搜&#xff09; 2.对优化解法的优化&#xff1a;把已经计算过的…...

已发布金融国家标准目录(截止2024年3月)

已发布金融国家标准目录2024年3月序号标准编号标准名称...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...