6、Redis系统-数据结构-04-Hash

news2024/9/22 23:25:55

四、哈希表(Hashtable)

哈希表是一种高效的键值对数据结构,通过散列函数将键映射到表中的位置,实现快速的插入、删除和查找操作。Redis 广泛使用哈希表来实现 Hash 对象和数据库的键值存储。以下将从结构设计、哈希冲突与链式哈希、rehash、渐进式哈希和哈希触发条件等角度详细介绍 Redis 中的哈希表。

1. 结构设计

在 Redis 中,哈希表(dict)由两个哈希表数组(dictht)组成,用于实现渐进式 rehash,以应对数据量增大时的性能问题。每个哈希表数组包含一个哈希表节点(dictEntry)的指针数组。哈希表节点用于存储实际的键值对,并通过链地址法处理哈希冲突。

哈希表结构
typedef struct dictht {
    dictEntry **table;    // 哈希表数组
    unsigned long size;   // 哈希表大小
    unsigned long sizemask;  // 哈希表大小掩码,用于计算索引值
    unsigned long used;   // 哈希表中已使用的节点数量
} dictht;

typedef struct dict {
    dictType *type;       // 类型特定函数
    void *privdata;       // 私有数据
    dictht ht[2];         // 哈希表,支持渐进式 rehash
    long rehashidx;       // rehash 索引,-1 表示没有进行 rehash
    unsigned long iterators;  // 当前正在运行的安全迭代器数量
} dict;

typedef struct dictEntry {
    void *key;            // 键
    union {
        void *val;        // 值
        uint64_t u64;     // 无符号整数值
        int64_t s64;      // 有符号整数值
        double d;         // 双精度浮点值
    } v;
    struct dictEntry *next;  // 指向下一个哈希表节点,解决冲突
} dictEntry;
主要字段介绍
  1. table:指向哈希表节点指针数组的指针。
  2. size:哈希表的大小,即哈希表数组的长度。
  3. sizemask:哈希表大小掩码,用于计算键的索引值。
  4. used:哈希表中已使用的节点数量。
  5. rehashidx:rehash 的索引,表示当前进行到哪个位置,-1 表示没有进行 rehash。
  6. type:指向哈希表类型特定函数的指针,用于实现不同类型的哈希表。
  7. privdata:指向私有数据的指针,可以用于存储与哈希表相关的额外信息。

2. 哈希冲突及链式哈希
哈希冲突

哈希冲突是指不同的键通过哈希函数计算得到相同的索引值,从而映射到哈希表数组的同一位置。哈希冲突是哈希表的一种常见问题,需要有效的处理机制来解决。

链式哈希

链式哈希是一种解决哈希冲突的常用方法。它通过链表的形式,将所有哈希值相同的键值对连接在一起。每个哈希表数组的元素(dictEntry)都指向一个链表的头节点,当发生哈希冲突时,新节点被插入到链表的头部。

typedef struct dictEntry {
    void *key;            // 键
    union {
        void *val;        // 值
        uint64_t u64;     // 无符号整数值
        int64_t s64;      // 有符号整数值
        double d;         // 双精度浮点值
    } v;
    struct dictEntry *next;  // 指向下一个哈希表节点,解决冲突
} dictEntry;
插入操作

在哈希表中插入键值对时,Redis 首先计算键的哈希值,并将其映射到哈希表数组中的一个位置。如果该位置已经有其他节点,则通过链地址法将新节点插入到链表的头部。

int dictAdd(dict *d, void *key, void *val) {
    dictEntry *entry = dictAddRaw(d, key);
    if (!entry) return DICT_ERR;
    dictSetVal(d, entry, val);
    return DICT_OK;
}
查找操作

在哈希表中查找键对应的值时,Redis 通过计算键的哈希值来确定其在哈希表数组中的位置,然后遍历链表查找对应的键值对。

dictEntry *dictFind(dict *d, const void *key) {
    if (d->ht[0].size == 0) return NULL;
    dictEntry *he = dictFindRaw(d, key);
    if (he == NULL) return NULL;
    return he;
}
删除操作

在哈希表中删除键值对时,Redis 同样通过计算键的哈希值来确定其位置,然后遍历链表找到对应的节点并将其删除。

int dictDelete(dict *d, const void *key) {
    if (dictSize(d) == 0) return DICT_ERR;
    if (dictDeleteRaw(d, key) == DICT_OK) {
        if (d->ht[0].used == 0) _dictReset(&d->ht[0]);
        return DICT_OK;
    }
    return DICT_ERR;
}
3. rehash
rehash 的必要性

随着哈希表中元素数量的增多,哈希表的负载因子(load factor)会不断增大,从而影响性能。为了维持哈希表的性能,Redis 需要进行 rehash 操作,即重新分配哈希表的大小,并将原有的键值对重新分布到新的哈希表中。

rehash 过程
  1. 初始化新哈希表:当需要进行 rehash 时,首先为哈希表分配新的哈希表数组,并调整新哈希表的大小。
  2. 迁移节点:将旧哈希表的所有节点逐个迁移到新哈希表中。迁移过程中,计算每个节点的新哈希值,并将其插入到新哈希表的对应位置。
  3. 完成 rehash:当所有节点都迁移完成后,释放旧哈希表的内存,将新哈希表替换为当前哈希表。
void _dictRehashStep(dict *d) {
    if (d->iterators == 0) dictRehash(d, 1);
}
4. 渐进式 rehash
渐进式 rehash 的基本思想

渐进式 rehash 的基本思想是:将哈希表的扩容操作分摊到多次操作中完成,而不是一次性完成,从而避免一次性 rehash 带来的性能问题。通过渐进式 rehash,Redis 可以在保证高效操作的同时,平滑地完成哈希表的扩容。

渐进式 rehash 的具体实现
  1. 分阶段迁移:在每次对哈希表进行增删查改操作时,逐步将旧哈希表的节点迁移到新哈希表中。每次操作迁移一部分节点,直到旧哈希表的所有节点都迁移完成。
  2. 维护 rehash 状态:在进行 rehash 过程中,Redis 维护一个 rehash 索引(rehashidx),表示当前迁移到哪个位置。每次操作完成后,rehash 索引会相应更新,直到所有节点迁移完成。
  3. 完成 rehash:当所有节点迁移完成后,释放旧哈希表的内存,将新哈希表替换为当前哈希表。
void _dictRehashStep(dict *d) {
    if (d->iterators == 0) dictRehash(d, 1);
}
渐进式 rehash 的优点
  1. 平滑过渡:通过逐步迁移节点,避免了一次性 rehash 带来的性能波动。
  2. 低延迟:每次操作只迁移一部分节点,保证了每次操作的时间复杂度不会过高,从而降低延迟。
5. 哈希触发条件

哈希表的 rehash 触发条件主要有两个:

  1. 负载因子:当哈希表的负载因子超过一定阈值时,触发 rehash 操作。负载因子等于已使用的节点数量除以哈希表的大小。Redis 的默认阈值是 1,当负载因子超过 1 时,会触发 rehash。
  2. 内存使用情况:当 Redis 内存使用情况达到

一定水平时,也会触发 rehash 操作,以保证内存的高效使用。

通过这两个条件,Redis 可以在适当的时候进行哈希表的 rehash,从而维持哈希表的性能和内存利用率。

结论

通过上述解析,我们可以更好地理解哈希表的设计思想和实现原理,从而在实际开发中更好地利用哈希表提供的优势。在 Redis 中,哈希表通过高效的键值对存储和渐进式 rehash 机制,实现了高性能和低延迟的操作,适用于多种场景如键值存储、缓存等。了解这些优化策略,可以帮助我们在实际应用中更好地利用 Redis 的性能和功能。

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

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

相关文章

【学术会议征稿】第五届计算机工程与智能控制学术会议(ICCEIC 2024)

第五届计算机工程与智能控制学术会议(ICCEIC 2024) 2024 5th International Conference on Computer Engineering and Intelligent Control 第五届计算机工程与智能控制学术会议(ICCEIC 2024)将于2024年10月18日至22日在广州举办&#xff0…

04-Haproxy搭建Web群集

理论讲解 Haproxy 是目前比较流行的一种群集调度工具,同类群集调度工具有很多,如LVS 和Nginx。相比较而言,LVS 性能最好,但是搭建相对复杂:Nginx的upstream模块支持群集功能,但是对群集节点健康检查功能不强&#xff…

tiff图片怎么转jpg?值得介绍的四种tiff转jpg方法

tiff图片怎么转jpg?jpg使用有损压缩技术,可以显著减小文件大小。这使得jpg文件更适合在网络上传输和在设备上存储。而且,PG格式被各种浏览器、图像查看器、编辑软件以及社交媒体平台广泛支持,使得分享和查看图片更加方便。如果需要…

tableau条形图绘制 - 2

tableau条形图绘制 1. 条形图绘制-11.1 创建工作表1.2 修改工作表名称1.3 条形图绘制1.4 显示标签1.5 行列转换 2. 条形图绘制-22.1 新建工作表2.2 修改工作表名称2.3 条形图绘制2.4 价格度量选平均值2.5 标签度量选平均值2.6 升序,整个视图显示2.7 行列转换 3. 堆积…

叹为观止|四款让人赞不绝口的优质软件,越用越上瘾

不说闲话直接上狠货,下面神仙软件,都值得使用。 Smart Defrag 说起电脑运行慢或者抽风,磁盘碎片就是让电脑变得又卡又不稳定的元凶之一。 不过Smart Defrag就算是新手小白也能操作,它里面藏着一个超强的碎片整理引擎&#xff0…

DevEco Studio No device 无法识别 usb 设备 - 鸿蒙

DevEco Studio IDE 版本与手机系统版本升级后出现了 USB 连接设备后 IDE 无法识别 no device 的情况出现; 解决办法 首先,确定当前 DevEco Studio 的 IDE 版本与移动设备的大版本保持一致; 其次,在版本相互匹配的情况下,查看移动设备是否开启了开发者模式与 USB 调试,具体步骤…

短视频文学剧本:成都柏煜文化传媒有限公司

短视频文学剧本,是创作者对现实世界的一次微缩重构。在这个被精心设计的空间里,时间被压缩,空间被浓缩,但每一个细节都经过精心雕琢,力求在有限的时间内展现出最大的信息量与情感深度。成都柏煜文化传媒有限公司从人物…

南方SouthMap:测绘世界的利器

在现代测绘领域,南方SouthMap软件无疑是一款不可或缺的工具。作为一名长期使用这款软件的用户,我深深感受到它在工作中的重要性和便利性。SouthMap不仅仅是一款软件,更是测绘工作者的得力助手,帮助我们在复杂的地理信息数据处理中…

9.pwn 栈溢出原理

栈溢出简介 函数中的存储在栈中的局部变量数组边界检查不严格发生越界写,造成用户输入覆盖到缓冲区外的数据内容, 由于栈中同时存在着与函数调用参数的相关信息,栈溢出可以导致控制流劫持 基础栈溢出(hello world in pwn) 多数情况下我们需…

掌握【Python异常处理】:打造健壮代码的现代编程指南

目录 ​编辑 1. 什么是异常? 知识点 示例 小李的理解 2. 常见的内置异常类型 知识点 示例 小李的理解 3. 异常机制的意义 知识点 示例 小李的理解 4. 如何处理异常 知识点 示例 小李的理解 5. 抛出异常 知识点 示例 小李的理解 6. Python内置…

linux学习week2+3

linux学习 九.linux磁盘分区、挂载 3.磁盘情况查询 命令:df -h 注意:使用率到80%以上就要清理了 查询指定目录的磁盘占用情况:du -d 目录 其它参数: -s:指定目录占用大小汇总 -h:带计量单位 -a&#xff…

直播平台集成美颜工具详解:视频美颜SDK开发指南

本篇文章,小编将详细介绍如何在直播平台中集成美颜工具,帮助开发者更好地理解视频美颜SDK的开发过程。 一、美颜工具的作用和原理 1.1 美颜工具的作用 美颜工具主要用于提升直播视频的画面质量,让主播和观众在镜头前看起来更加美观。这些功…

解决Windows server 2022环境下,远程桌面连接仅允许两个用户同时登录问题,亲测有效!

文章目录 问题描述解决服务器远程桌面限制:第一步:给服务器开启远程访问权限解决服务器远程桌面限制:第一种方案:临时开启多用户远程桌面限制(120天)解决服务器远程桌面限制:第二种方案&#xf…

视频图文理解关联技术与创业团队(二)

上一篇:google gemini1.5 flash视频图文理解能力初探(一)提到了gemini 1.5 flash 可以对视频进行理解以及分析,但是整体在检索任务上效果不佳。 这几天参加了人工智能大会 网上收集,看一看有相似能力的一些技术点、创…

越来越多用户和商家选择小程序商城的原因是什么?小程序商城怎么搭建?

得益于小程序的便捷性,越来越多的用户选择在小程序商城购物,越来越多的商家也开始搭建自己的小程序商城。背后原因是什么呢?小程序商城怎么搭建? 用户为何青睐小程序商城? 1、便捷性 小程序商城无需下载安装&#xff…

无线领夹麦克风哪个牌子好,领夹麦克风十大品牌推荐

​演讲、表演或录制视频时,高质量的无线麦克风能极大提升整体体验。它保证了声音的清晰度和真实感,让演讲者或表演者更自信舒适。基于市场研究和用户体验,我挑选了几款表现突出的无线领夹麦克风,均为我个人使用过并推荐的产品&…

复古也疯狂:诺基亚105新款,4MB内存竟能干这些大事

今天我带着一丝怀旧和一份惊喜,想和你们分享一款特别的产品——诺基亚105(2024)2G功能手机。在智能手机充斥的今天,这样一款功能手机似乎显得格外与众不同。 它不仅是对经典的一次致敬,更在细节上融入了现代的便利。让…

tauri + vue3 如何实现在一个页面上局部加载外部网页?

🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&…

设计模式探索:建造者模式

1. 什么是建造者模式 建造者模式 (Builder Pattern),也被称为生成器模式,是一种创建型设计模式。 定义:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。 建造者模式要解决的问题: 建造者模…

Vue脚手架搭建及vue项目创建---大屏

灵感在于上数据可视化这门课程,需要做大屏系统。 下面是使用VS Code搭建vue脚手架并创建项目。 第一步 安装node.js和vscode node.js在官网下载后安装,安装后输入命令看是否安装好,若没安装好,自行去网上搜索怎么配置环境变量&a…