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

Redis性能滑坡:哈希表碰撞的不速之客【redis第二部分】

Redis性能滑坡:哈希表碰撞的不速之客

  • 前言
  • 第一部分:Redis哈希表简介
  • 第二部分:哈希表冲突原因
  • 第三部分:Redis哈希函数
  • 第四部分:哈希表冲突的性能影响
  • 第五部分:解决冲突策略
  • 第六部分:redis是如何解决hash冲突的

前言

Redis是一款强大的内存数据库,但在处理大规模数据时,可能会遇到性能下滑的问题。其中一个潜在的性能瓶颈是Redis哈希表中的冲突。这些冲突可能导致操作变慢,甚至影响应用程序的响应时间。在这篇博客中,我们将探讨Redis哈希表冲突的根本原因,以及如何解决它们。无论您是一位Redis用户、开发人员还是系统管理员,这篇博客将为您提供宝贵的见解,帮助您优化Redis性能。

第一部分:Redis哈希表简介

Redis哈希表是一个数据结构,它允许将多个键值对存储在一个Redis键下。与普通的Redis字符串键不同,哈希表中的值本身也可以包含键值对,这使得它在存储和检索多个相关信息时非常有用。下面是Redis哈希表的基本工作原理:

  1. 存储键值对:Redis哈希表使用一个唯一的键作为标识,你可以将多个键值对与这个键相关联。这个键相当于哈希表的名称,它可以用来区分不同的哈希表。每个键值对都有一个字段(field)和一个值(value),你可以将它们存储在哈希表中。

  2. 访问键值对:要访问Redis哈希表中的键值对,你需要提供哈希表的键和字段。通过指定键和字段,你可以获取相应的值。这是哈希表的快速查找特性,因为它不需要遍历整个数据结构,而是直接访问指定字段的值。

  3. 哈希算法:Redis使用哈希算法来高效地存储和检索数据。当你执行哈希表操作时,Redis会使用哈希算法来确定字段在内部存储结构中的位置,从而快速定位和访问值。

  4. 灵活性:Redis哈希表不仅用于存储简单的键值对,还可以存储复杂的数据结构。字段和值都可以是字符串,因此你可以存储各种类型的数据,包括文本、数字、甚至嵌套的哈希表。

在Redis中,你可以使用一系列命令来操作哈希表,包括HSET(设置字段值)、HGET(获取字段值)、HDEL(删除字段)、HGETALL(获取所有字段和值)等等。这些命令让你能够方便地管理和检索数据,适用于许多应用场景,如缓存、配置存储、计数器等。

在实际的软件开发中,你可以使用适当的客户端库(如Jedis、redis-py等)来与Redis服务器交互,实现Redis哈希表的操作,并添加注释以提高代码的可维护性和可读性。

第二部分:哈希表冲突原因

哈希表中发生冲突的主要原因包括哈希函数碰撞和数据增长。下面详细探讨这两个原因:

  1. 哈希函数碰撞

    • 哈希函数设计不佳:如果哈希函数不足够均匀地将键映射到哈希表的索引,就会导致碰撞。一个好的哈希函数应该尽可能均匀地分布键,以减少碰撞的发生。如果哈希函数过于简单,例如只取键的某一部分作为哈希值,那么碰撞的概率就会增加。

    • 数据分布不均匀:即使哈希函数很好,但如果数据的分布不均匀,某些键的哈希值集中在同一索引位置,就会导致碰撞。这可能是因为数据本身的特性,如大量的相似前缀或特定数据分布模式。

    • 哈希表大小不合适:如果哈希表的大小不足以容纳要存储的数据,也可能导致碰撞。一个过小的哈希表容易使不同的键映射到同一位置。

  2. 数据增长

    • 插入新数据:当不断往哈希表中插入新数据时,数据的数量逐渐增加,这可能导致已有的索引位置上存储的数据量增加,从而增加了碰撞的概率。这种情况下,通常需要考虑动态调整哈希表的大小,以适应更多的数据。

    • 删除数据:数据的删除也可能导致冲突。当你从哈希表中删除数据时,会留下空的索引位置。如果插入新数据时正好哈希到这些空位置,就会发生冲突。因此,一些哈希表实现会采用特定策略来处理删除操作,以减少碰撞。

解决哈希表中的碰撞通常需要采用一种碰撞解决方法,如拉链法(Chaining)或线性探测法(Linear Probing)。这些方法允许在同一索引位置存储多个键值对,以处理碰撞情况。不同的解决方法在性能和实现复杂性上有所不同,你可以根据应用的要求选择合适的方法。

在软件开发中,对于哈希表的操作和处理碰撞的逻辑,通常需要添加注释以提高代码的可维护性和可读性,同时需要监控数据增长情况,以及根据实际需求调整哈希表的大小,以降低碰撞的概率。

第三部分:Redis哈希函数

Redis中的哈希函数对于哈希表的性能至关重要。哈希函数的作用是将键(key)映射到哈希表中的索引位置,以实现快速的存储和检索操作。以下是关于Redis中哈希函数的工作方式以及它对哈希表性能的影响的解释:

  1. 哈希函数的作用

    • 键映射:哈希函数将键转换为一个数字,这个数字通常被称为哈希值。这个哈希值确定了键在哈希表中的存储位置。

    • 均匀分布:一个好的哈希函数应该尽可能均匀地将键分布到哈希表的各个索引位置,以减少碰撞的概率。碰撞是指多个不同的键具有相同的哈希值,导致它们存储在相同的索引位置,需要额外的处理来解决。

  2. 哈希函数的性能影响

    • 碰撞的影响:如果哈希函数不均匀地将键映射到索引位置,就会导致碰撞。碰撞会降低哈希表的性能,因为在发生碰撞时,需要额外的步骤来解决,例如使用拉链法(Chaining)或线性探测法(Linear Probing)。

    • 查找效率:一个好的哈希函数应该能够快速地映射键到索引位置,从而实现高效的查找操作。如果哈希函数的计算成本很高,将会影响哈希表的性能。

    • 分布均匀性:如果哈希函数无法实现均匀的键分布,某些索引位置可能会存储更多的键,而其他位置则较少。这会导致不均匀的负载,降低了哈希表的性能,因为某些位置的操作会更耗时。

  3. 如何选择好的哈希函数

    • 均匀分布:选择一个哈希函数要确保它能够将键均匀地分布到哈希表的索引位置。这通常需要考虑键的不同部分,如字符、数字等,以及哈希函数的设计。

    • 计算效率:哈希函数的计算效率也是一个关键因素。它不应该过于复杂,以免成为性能瓶颈。同时,哈希函数应该能够在不同的编程语言和平台上实现。

在Redis中,哈希函数的选择通常是内部实现的一部分,而用户通常无需过多关注。然而,了解好的哈希函数如何工作以及如何影响性能可以帮助你更好地理解Redis的内部机制,并在需要时更好地调整哈希表的大小以应对数据增长。同时,注释代码以解释哈希函数的工作方式也有助于代码的可维护性。

第四部分:哈希表冲突的性能影响

哈希表冲突对Redis性能有实际的影响,尤其是在读写操作的延迟方面。以下是一些哈希表冲突可能产生的性能影响:

  1. 读操作性能影响

    • 查找时间增加:当哈希表中存在冲突时,读操作需要额外的步骤来处理碰撞。通常,这涉及在冲突的位置上搜索目标键,这可能需要遍历链表(如果使用了拉链法)或者执行线性探测。这导致了额外的查找时间,从而增加了读操作的延迟。

    • 不均匀负载:如果冲突严重,某些索引位置可能会存储大量的键值对,而其他位置则较少。这导致不均匀的负载,某些操作需要更长的时间来找到目标键,而其他位置则可能更快。这种不均匀性会使部分读操作的延迟增加。

  2. 写操作性能影响

    • 冲突的处理:在写操作中,当新键与已有键产生冲突时,需要执行额外的步骤来处理碰撞。具体处理方式取决于哈希表的解决碰撞方法,如拉链法或线性探测。这些额外的操作会增加写操作的延迟。

    • 扩容开销:当哈希表中的数据量不断增加,为了减少碰撞,Redis可能需要自动扩容哈希表。这涉及创建新的哈希表,重新计算哈希值,并将现有数据迁移到新表中。这个过程会带来一定的性能开销,并在扩容期间可能导致写操作的延迟。

  3. 缓存命中率下降

    • 冲突降低了缓存命中率:如果哈希表中的冲突严重,缓存命中率可能会下降,因为某些数据在哈希表中无法高效存储和检索。这意味着更多的读操作需要到后端存储系统(如数据库)中查找数据,从而导致性能下降。

为了应对哈希表冲突对Redis性能的影响,可以采取以下措施:

  • 选择合适的哈希函数,以减少碰撞的发生,提高数据均匀分布性。
  • 监控哈希表的负载情况,及时调整哈希表的大小以应对数据增长。
  • 使用合适的碰撞解决方法,如拉链法或线性探测,以降低读写操作的延迟。
  • 考虑使用Redis的持久性选项,以避免数据丢失,尤其在扩容哈希表时。

总之,哈希表冲突可以对Redis性能产生负面影响,但通过选择适当的策略和合理的配置,可以降低这些影响,保持高性能的Redis实例。

第五部分:解决冲突策略

解决哈希表冲突的策略通常包括以下几种方法:

  1. 拉链法(Chaining)

    • 工作原理:在这种策略中,每个哈希表的槽(索引位置)不仅可以存储一个键值对,而是可以存储一个链表或其他数据结构。当冲突发生时,新的键值对被附加到链表上,而不是覆盖旧的键值对。这样,同一索引位置可以存储多个键值对。

    • 优点:拉链法简单且易于实现,对于处理冲突效果良好,不需要频繁扩容哈希表。

    • 缺点:当链表变得很长时,查找特定键的性能可能会下降,因为需要遍历链表。

  2. 线性探测法(Linear Probing)

    • 工作原理:在线性探测法中,当冲突发生时,哈希表会顺序查找下一个可用的槽,直到找到一个空槽来存储键值对。这意味着键值对被依次存储在哈希表中,而不是在链表中。

    • 优点:线性探测法不需要额外的数据结构来存储键值对,它可以更好地利用内存,减少链表的开销。

    • 缺点:性能可能在连续冲突较多的情况下下降,因为可能需要查找多个槽才能找到可用位置。

  3. 再哈希(Rehashing)

    • 工作原理:再哈希是一种处理冲突的策略,其中当冲突发生时,哈希表会使用另一个哈希函数来计算新的索引位置,直到找到一个空槽来存储键值对。

    • 优点:再哈希方法可以减少冲突的发生,并在一定程度上提高性能,因为新的哈希函数可能更均匀地分布键。

    • 缺点:重新哈希可能是一个耗时的操作,因为需要重新计算和移动数据,此时哈希表可能不可用。

  4. 二次探测、双散列等

    • 除了上述方法,还存在其他方法,如二次探测(quadratic probing)、双散列(double hashing)等,它们在处理冲突时采用不同的探测策略和哈希函数。这些方法适用于不同的情况和性能需求。

第六部分:redis是如何解决hash冲突的

Redis解决哈希冲突的方式,就是链式哈希。就是指同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接。

在这里插入图片描述

⬆️:上图可以看到,entry1、entry2和entry3都存到了哈希桶3号位置,而解决冲突的方式就是把它们连起来。这样就形成一个链表,也叫做哈希冲突链。

❓:但是如果这了链表越来越长,那么效率就会降低,对此Redis会对哈希表做rehash操作。rehash也就是增加现有的哈希桶数量,让逐渐增多的entry元素能在更多的桶之间分散保存,减少单个桶中的元素数量,从而减少单个桶中的冲突。

✌️:为了使rehash操作更高效,Redis默认使用了两个全局哈希表:哈希表1和哈希表2。一开始,当你刚插入数据时,默认使用哈希表1,此时哈希表2并没有被分配空间。随着数据逐步增多,Redis开始执行rehash,这个过程分为三步:

  • 给哈希表2分配更大的空间,例如是当前哈希表1大小的两倍;
  • 把哈希表1中的数据重新映射并拷贝到哈希表2中;
  • 释放哈希表1的空间。

⏭:到此,我们就可以从哈希表1切换到哈希表2,用增大的哈希表2保存更多数据,而原来的哈希表1留作下一次rehash扩容备用。

⏭:这个过程看似简单,但是第二部涉及大量的数据拷贝,如果一次性把哈希表1中的数据都迁移完,会造成Redis线程阻塞,无法服务其他请求。此时,Redis就无法快速访问数据了。

♻️:为了避免这个问题,Redis采用了渐进式rehash

简单来说就是在第二步拷贝数据时,Redis仍然正常处理客户端请求,每处理一个请求时,从哈希表1中的第一个索引位置开始,顺带着将这个索引位置上的所有entries拷贝到哈希表2中;等处理下一个请求时,再顺带拷贝哈希表1中的下一个索引位置的entries。如下图所示:
在这里插入图片描述

👴:这样就可以避免因为一次导入导致大量的开销,从而避免了耗时操作。

🌗:对于String类型来说,找到哈希桶就能直接增删查改,所以,哈希表的O(1)操作复杂度就是它的复杂度。但是对于集合来说虽然找到了哈希桶,但是还要在集合中再进一步操作。

相关文章:

Redis性能滑坡:哈希表碰撞的不速之客【redis第二部分】

Redis性能滑坡:哈希表碰撞的不速之客 前言第一部分:Redis哈希表简介第二部分:哈希表冲突原因第三部分:Redis哈希函数第四部分:哈希表冲突的性能影响第五部分:解决冲突策略第六部分:redis是如何解…...

科技与教育的盛宴——探讨监控易在82届教装展的新机遇

在第82届中国教育装备展示会这个融合了科技与教育的盛宴上,监控易将展现其最新的教育信息化解决方案和技术创新成果。这不仅是一次产品的展示,更是一次理念、技术与需求的交流和碰撞。在这里,我们将一同探讨在科技日新月异的今天,…...

Bazzite:专为 Steam Deck 和 PC 上的 Linux 游戏打造的发行版

导读对于一个专为 Linux 游戏定制的发行版,你是否感兴趣呢?如果答案是肯定的,那么我们为你准备了绝佳选择。 Bazzite 是一个新推出的基于 Fedora 的发行版,它是为 Linux 桌面上的游戏,以及越来越火热的 Steam Deck 定…...

【MySQL】数据库数据类型

文章目录 1. 整体概要2. 数值类型(有符号) tinyint 创建表(无符号) tinyint 创建表bit类型float 类型(无符号)floatdecimal 3. 二进制类型char类型varchar类型 4. 日期时间日期时间类型 5. string 类型enum类型和set类型enum类型和set类型的查找在枚举中的查找在set中的查找 1.…...

计算机组成原理 new07 真值和机器数 无符号整数 定点整数 定点小数 $\color{red}{Δ}$

文章目录 真值和机器数 无符号整数无符号整数的定义无符号整数的特征无符号整数的表示范围无符号整数的加法无符号数的减法 有符号整数(定点整数)有符号整数的定义原码原码的特点反码反码的特点补码补码的特点快速求解n位负数补码的方法为什么补码能够多表示一个范围(重点)变形…...

基于SSM的文化培训学校网站的设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…...

gitee-git使用

克隆gitee某代码仓库某分支流程 1.克隆远程gitee仓库某分支到本地 2.如果克隆gitee仓库是私有的系统会弹出弹框让你输入gitee的账户和密码 3.克隆远程分支完成 git所需命令 克隆远程仓库到本地 git clone 仓库URLgit克隆远程分支到本地 git clone -b 分支名 仓库URLgit 拉…...

欧拉图(Euler Graph)

这种「一笔画」问题与欧拉图或者半欧拉图有着紧密的联系,下面给出定义: 通过图中所有边恰好一次且行遍所有顶点的通路称为 欧拉通路; 通过图中所有边恰好一次且行遍所有顶点的回路称为 欧拉回路; 具有欧拉回路的无向图称为 欧拉图; 具有欧拉通路但不具有欧拉回路的无向图…...

【安全体系架构】——零信任网络架构

什么是零信任网络架构? 零信任网络架构是一种网络和信息安全模型,它将传统的信任模型颠覆,不再信任内部或外部用户、设备或网络。相反,它将每个访问请求都视为不受信任,要求对每个用户、设备和流量都进行认证和授权&a…...

mybatis动态sql一对多查询

在数据库设计中,一对多关系是非常多的,例如消息通知和附件,一个消息通知中往往会包含多个附件,这种情况下使用mybatis动态sql可以很方便的查询出来。 1、数据库设计 消息表:sys_message CREATE TABLE sys_message (i…...

Leetcode.2316 统计无向图中无法互相到达点对数

题目链接 Leetcode.2316 统计无向图中无法互相到达点对数 rating : 1604 题目描述 给你一个整数 n n n ,表示一张 无向图 中有 n n n 个节点,编号为 0 0 0 到 n − 1 n - 1 n−1 。同时给你一个二维整数数组 e d g e s edges edges ,其…...

介绍机器学习中CatBoost工具的详细使用指南

在机器学习的动态世界中,Python 是创新背后的驱动力,专业人士必须使用正确的工具。CatBoost 就是这样一个工具,以其卓越的速度和准确性悄然改变了该领域。在本指南中,我们将深入研究 Python 3 中的 CatBoost,涵盖基础知识、高级技术和实际示例,包括使用示例数据集和绘图进…...

操作系统【OS】线程与进程的比较

进程 线程 是什么的单位? 是资源分配的基本单位 是调度的基本单位 不能共享什么? 不能共享虚拟地址空间 不能共享栈指针 可以共享什么? 拥有一个完整的资源平台 每个进程都有独立的地址空间和资源 除了共享全局变量,不允许其他进程访问 某进程中的线程…...

在Mac上使用安卓桌面模式

在安装Homeblew的基础上 替换国内源 export HOMEBREW_API_DOMAIN"https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/api" export HOMEBREW_BREW_GIT_REMOTE"https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git" brew update 安装Scrcpy …...

YOLO目标检测——人脸口罩佩戴数据集【(含对应voc、coco和yolo三种格式标签】

实际项目应用:公共场所监控场景下的大密度人群检测是否佩戴口罩,以及戴口罩的人证比对(安检刷脸不用摘口罩)、手机解锁、刷脸考勤等身份认证场景。数据集说明:人脸口罩佩戴检测数据集,真实场景的高质量图片…...

mongodb如何多表查询,如同时查询店铺以及里面对应的商品

多表查询场景介绍 一种很常见的场景,比如电商首页中,需要同时展示最近比较火热的店铺,以及直接展示店铺里对应的商品。或者用户下单之后购物车里可以看到所选的商品以及对应的店铺。如果不知道如何用mongodb自带的查询语句快速查询的话&#…...

Linux环境修改服务器时间和网络时间保持一致

目录 介绍UTC和CST 修改时区 修改时间 介绍UTC和CST UTC是协调世界时,是全球统一的时间标准。UTC的时间是基于原子钟计算的,以秒为单位,不受夏令时等影响。世界各地都可以通过UTC来同步时间。 CST是中央标准时间,相当于UTC-6…...

CUDA学习笔记6——事件计时

事件计时 CUDA事件是直接在GPU上实现的,因此它们不适用于对同时包含设备代码和主机代码的混合代码计时。 cudaEventCreate 创建一个事件cudaEventRecord 记录一个事件cudaEventElapsedTime 计算两个事件之间经历的时间,第一个参数为某个浮点变量的地址…...

使用vscode调试ffmpeg源码

ffmpeg的编译配置 # --enable-debug 设置为调试级别 # --disable-stripping 如果不加此选项,会strip去掉符号信息 ./configure --prefix{output_path} --enable-debug --disable-stripping make -j10VSCode的配置 将以下文件对比替换工程.vscode目录下的相同文件 …...

微信小程序--数字化会议OA系统之首页搭建

一、Flex弹性布局 布局的传统解决方案,基于盒状模型,依赖 display属性 position属性 float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。 2009年,W3C提出了一种新的方案—-Flex布局,可…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

Vue ③-生命周期 || 脚手架

生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

小木的算法日记-多叉树的递归/层序遍历

🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...