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 冲突时能够有效地平衡性能和复杂度,确保在各种使用场景下都能提供高效的数据存储和检索服务。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

eNSP网络基本配置

1.配置设备名称 网络上一般不会配属一台设备,管理员需要对这些设备进行统一管理。在进行设备调试的时候,首要任务是配置设备名称,设备名称用来唯一标识一台设备。 例如通过以下操作将设备名称设置为testA ? //可以查看用户视图…

AnaTraf | 提升网络性能:深入解析网络关键指标监控、TCP重传与TCP握手时间

AnaTraf 网络性能监控系统NPM | 全流量回溯分析 | 网络故障排除工具 在当今的数字化时代,网络的稳定性和性能对企业的运营效率至关重要。无论是内部通信、应用程序的运行,还是对外提供服务,网络都发挥着关键作用。对于网络工程师或IT运维人员…

雨情教务排课系统源码

PC端的雨情教务排课系统,是一款集功能性、实用性与便捷性于一体的教育管理工具。它全面支持班级设置功能,能够轻松管理不同年级、不同专业的班级信息,为后续的排课工作奠定坚实基础。在课程设置方面,系统允许管理者根据教学计划&a…

安装OpenResty

OpenResty OpenResty 是一个基于 Nginx的高性能 Web 平台,用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。具备下列特点: 具备Nginx的完整功能 基于Lua语言进行扩展,集成了大量精良的 Lua 库、第三方模块…

Java最全面试题->Java基础面试题->JavaWeb面试题->Git/SVN面试题

文章目录 Git/SVN面试题Git和SVN有什么区别?SVN优缺点?Git优缺点?说一下Git创建分支的步骤?说一下Git合并的两种方法以及区别?Git如何查看文件的提交历史和分支的提交历史?什么是 git stash?什么是git sta…

uniapp修改input中placeholder样式

Uniapp官方提供了两种修改的属性方法&#xff0c;但经过测试&#xff0c;只有 placeholder-class 属性能够生效 <input placeholder"请输入手机验证码" placeholder-class"input-placeholder"/><!-- css --> <style lang"scss" s…

KBPC1010-ASEMI新能源专用方桥KBPC1010

编辑&#xff1a;ll KBPC1010-ASEMI新能源专用方桥KBPC1010 型号&#xff1a;KBPC1010 品牌&#xff1a;ASEMI 封装&#xff1a;KBPC-4 安装方式&#xff1a;直插 批号&#xff1a;2024 现货&#xff1a;50000 正向电流&#xff08;Id&#xff09;&#xff1a;10A 反向…

芯海休眠唤醒

这个电路要钱&#xff0c;降本需要去掉这个电路&#xff0c;让软件完全实现开关机的功能。 1、当按键按下的时候&#xff0c;K1下面接地&#xff0c;R12下面为低电平&#xff0c;同时BAT在左边供电&#xff0c;为高电平&#xff0c;Q2MOS管导通&#xff0c;给板子供电。 2、当…

【and design ProTable组件rowClassName属性进行判断修改行样式】

代码解析 注&#xff1a;行改变基于css效果 【导入css文件】 效果展示 代码块 自己导入cssrowClassName{(record)>{return record.jibie"高"?"row-style":""}}

Linux_进程终止_进程等待_进程替换

进程终止 不知道大家想过没有&#xff0c;我们写的main()函数的返回值是返回给谁的呢&#xff1f;其实是返回给父进程或者系统的。 int main() {std::cout << "hello" << std::endl;return 10; }运行该代码&#xff0c;输入hello&#xff0c;没问题&am…

I\O进程线程(Day32)

一、学习内容 进程之间的通信(nterprocess communication) 信号通信 概念 1> 信号通信中&#xff0c;多个进程只起到通知作用&#xff0c;没有数据传输的功能 2> 所谓信号通信&#xff0c;就是软件模拟的硬件的中断请求 3>原理图 信号处理方式 默认&#xff08;SIG_DF…

SpringBoot1~~~

目录 快速入门 依赖管理和自动配置 修改自动仲裁/默认版本号 starter场景启动器 自动配置 修改默认扫描包结构 修改默认配置 读取application.properties文件 按需加载原则 容器功能 Configuration Import ​编辑 Conditional ImportResource 配置绑定Configur…

华为云购买弹性云服务器(教程)

配置弹性云服务器 基础配置 实例 操作系统

『完整代码』坐骑召唤

创建一个按钮 作为召唤/消失坐骑的开关 将预制体放入指定文件夹 命名为Mount01 创建脚本并编写&#xff1a;CallMount.cs using UnityEngine; using UnityEngine.UI; public class CallMount : MonoBehaviour{public Button callBtn;GameObject mountPrefab;GameObject mountIn…

信息搜集 --子域名

1.证书查询 通过ssl证书指纹在crt.sh |证书搜索网站搜索 这些就是证书一样的 2.fofa等空间测绘平台查询 3.dns查询 https://dnsdumpster.com/ 4.威胁情报中心 360 微步等等 5.枚举 暴力破解 工具推荐&#xff1a;oneforall GitHub - shmilylty/OneForAll: OneForAll是一款…

windows 上面交叉编译 适合arm架构上的linux内核系统的qt 版本,源码编译

1. 在机器上确认系统信息 cat /proc/cpuinfomodel name : ARMv7 Processor rev 5 (v7l) arm 32位 BogoMIPS : 57.14 Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 CPU implementer : 0x41 CPU architecture: 7 …

【Linux】线程互斥与同步,生产消费模型(超详解)

目录 线程互斥 进程线程间的互斥相关背景概念 数据不一致问题 锁 深度理解锁 原理角度理解&#xff1a; 实现角度理解&#xff1a; 线程同步 条件变量 测试代码 生产消费模型 生产消费模型概念 编写生产消费模型 BlockingQueue &#xff08;1&#xff09;创建生产…

双十一宠物空气净化器哪款吸毛好而且噪音低?希喂、IAM、有哈真实测评

家人们谁懂啊&#xff0c;家里怎么会有一只这么爱掉毛的小猫咪啊&#xff0c;看着香香软软的&#xff0c;谁知道掉起毛来六亲不认啊&#xff0c;搞得我这个老母亲筋疲力尽啊&#xff0c;每天只想着清理它掉下来的浮毛&#xff0c;主要是还特别难清理。 所以后面入手了能吸毛的…

OpenAI o1复现:自动构造prm训练数据-OmegaPRM

作者&#xff1a;cmathx 原文&#xff1a;https://zhuanlan.zhihu.com/p/1477078851 openai o1复现中&#xff0c;有个比较关键的问题&#xff0c;怎么样自动化构造prm模型的训练数据&#xff1f;本文主要从代码层面&#xff0c;来解析OmegaPRM原理。 论文 Improve Mathemat…

Discuz | 起尔开发 传奇开服表游戏公益服发布论坛网站插件

Discuz | 起尔开发 传奇开服表游戏公益服发布论坛网站插件 插件下载&#xff1a;源码 - 起尔开发的插件下载 演示地址&#xff1a;discuz.72jz.com 标黄和非标黄自动分开 在标黄时间内显示在上面置顶&#xff0c;标黄过期后自动显示在下面白色区域。 后台可以设置非标黄默认…