Hash、HASHTABLE底层原理【Redis对象篇】

news2025/2/28 10:36:54

🏆 作者简介:席万里
⚡ 个人网站:https://dahua.bloggo.chat/
✍️ 一名后端开发小趴菜,同时略懂Vue与React前端技术,也了解一点微信小程序开发。
🍻 对计算机充满兴趣,愿意并且希望学习更多的技术,接触更多的大神,提高自己的编程思维和解决问题的能力。

文章目录

  • 1.hash是什么?
  • 2.适用场景
  • 3.常用操作
    • 1.写操作
    • 2.读操作
  • 4.原理
  • 5.总结
  • HASTABLE
    • 1.HASHTABLE简述
    • 2.HASHTABLE结构
    • 3.渐进式扩容,缩容

1.hash是什么?

Redis Hash是一个field、value都为string的hash表,存储在Redis的内存中。

2.适用场景

适用于O(1)时间字典查找某个field对应数据的场景,比如任务信息的配置,就可以任务类型为field,任务配置参数为value。

3.常用操作

  • 创建:HSET、HSETNX
  • 查询:HGETALL、HGET、HLEN、HSCAN
  • 更新:HSET、HSETNX、HDEL
  • 删除:DEL

1.写操作

1、HSET,为集合对应field设置value数据。字段+值。
HSET key field value [field value …]
[图片]

[图片]

2、HSETNX,如果field不存在,则为集合对应设置value数据。如果存在则不设置。
[图片]

3、HDEL,删除指定字段field,可以一次删除多个。
4、DEL,删除Hash对象。
5、HMSET,可以设置多个键值对。在Redis4.0之前,HSET只能设置单个键值对,4.0之后,弃用HMSET,改用HSET。

2.读操作

1、HGETALL,查找全部数据。
[图片]

2、HGET,查询field对应的value。
3、HLEN,查找Hash中元素总数。
4、HSCAN,从指定位置查询一定数量的数据。

4.原理

Hash底层有两种编码结构,压缩列表和HASHTABLE。同时满足以下两个条件,用压缩列表:

  1. Hash对象保存的所有值和键的长度都小于64字节;
  2. Hash对象元素个数少于512个。
    两个条件任何一条不满足,编码结构就用HASHTABLE。
    ZIPLIST其实就是在数据量小的时候将数据紧凑排列,对应到Hash,就是将field-value当做entry放入ZIPLIST。查找key的时间复杂度O(N)。
    [图片]

HASHTABLE在之前无序集合SET中也有应用,区别就是,在SET中value始终为null,但是Hash中是有对应的值。查找key的时间复杂度O(1)。
[图片]

5.总结

1、Hash的编码方式是什么?
一个是ZIPLIST,一个是HASHTABLE。ZIPLIST适用于元素较少且单个元素长度较小的情况,其他情况使用HASHTABLE。

2、HASH为什么要用两种编码方式?
采用两种编码方式的原因是ZIPLIST更节约内存,所以在小数据量使用,而数据多时,需要使用HASHTABLE提高更高的查找、更新性能。

HASTABLE

别,这个模块还没结束呢。学了SET和HASH之后,我们都见到了底层有一个叫HASHTABLE的结构,接下来就去探究一下这是个啥。

1.HASHTABLE简述

简单点说,就是哈希表。那么有什么用呢?
就好比一本书,如果让你一页一页去找是不是很麻烦,要是有一个目录可以直接根据关键字就能定位,是不是效率就更高了。

2.HASHTABLE结构

// redis 5.0.5
typedef struct dictht {
    dictEntry **table;    /* 哈希桶数组,指向实际的hash存储 */
    unsigned long size;   /* 哈希表大小(桶数) */
    unsigned long sizemask; /* 哈希表大小掩码 */
    unsigned long used;   /* 哈希表已使用的桶数量 */
} dictht;

[图片]

3.渐进式扩容,缩容

// redis 5.0.5
typedef struct dict {
    dictht ht[2];         /* 目前使用的两个哈希表(用于rehash) */
    dictType *type;       /* 数据类型 */
    void *privdata;       /* 私有数据(通常为 NULL),保存需要传给那些类型特定函数的可选参数*/
    long rehashidx;       /* 正在进行的 rehash 操作的桶索引 */
    unsigned long iterators; /* 迭代器数量 */
} dict;

为了实现渐进式扩容,redis没有直接把dictht暴露给上层,而是再封装一层,如上。
可以看到dict结构里面,包含了两个dictht结构,也就是两个HASHTABLE结构。dictEntry是链表结构,也就是用拉链法解决哈希冲突,用的头插法。
[图片]

实际上平时用的都是一个HASHTABLE,在触发扩容之后,就会两个HASHTABLE同时使用,以下是详细流程:

  1. 首先,为新Hash表ht[1]分配空间。新表大小为第一个大于等于原表2倍used(已使用的桶数量)的2次方幂。然后迁移ht[0]数据到ht[1]。在ReHash(是指重新计算键的哈希值和索引值)进行期间,每次对字典执行增删改查操作,程序会顺带迁移当前rehashidx在ht[0]上对应的数据,并更新偏移索引。同时,部分情况周期函数也会进行迁移。(这里解释一下这个rehashidx是什么意思:字典同时是拥有ht[0]和ht[1],将rehashidx设置为0,表示rehash开始;在rehash期间,每次对字典crud,会顺带将ht[0]哈希表在rehashidx索引上的所有kv rehash到ht[1],当rehash完成后rehashidx+1;随着字典不断操作,最终ht[0]所有键值都会被rehash到ht[1],这时将rehashidx设置为-1,表示操作结束。注意:在渐进式rehash的过程,如果有crud,如果index大于rehashidx,访问ht[0],否则访问ht[1]。)
  2. 然后,随着字典不断执行,最终在某个时间点上,ht[0]的所有键值都会被Rehash至ht[1],此时再将ht[1]和ht[0]指针对象互换,同时把偏移索引rehashidx的值设为-1,表示Rehash已完成。
    既然知道了扩容的流程,那么扩容时机是什么时候呢?
    redis会根据负载因子的情况来扩容:
  3. 负载因子大于等于1,说明此时空间已经非常紧张。
  4. 负载因子大于5,此时即使有复制命令,也要进行Rehash扩容。
    负载因子:k=ht[0].used / ht[0].size
    如果扩容太大,但是数据已经减少了,就需要进行缩容,缩容也是渐进式的。那么什么时机缩容呢?
    当负载因子小于0.1,即负载率小于10%,此时进行缩容,新表大小为第一个等于原表used的2次方幂。

总之,ZIPLIST、HASHTABLE面试超级热点,不仅学习这些大致思路,还要掌握一些细节。

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

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

相关文章

CentOS 二进制安装部署MongoDB 4.0

一、安装MongoDB 1. 下载 MongoDB 二进制文件 前往 MongoDB 官方下载页面(https://www.mongodb.com/try/download/community) 选择对应版本的 tar 包。 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.28.tgz 2. 解压并移动至目标目录 解压文件&#xff…

Redis篇-5--原理篇4--Lua脚本

1、概述 Redis 支持使用 Lua 脚本来执行复杂的操作,这为 Redis 提供了更强的灵活性和性能优化能力。通过 Lua 脚本,你可以在服务器端执行一系列命令,而不需要多次往返客户端与服务器之间,从而减少了网络延迟并提高了效率。此外&a…

新手上路,学Go还是Python

对于新手来说,Go和Python都是很好的编程语言,它们各有特点,以下是详细的对比来帮助你决定先学哪一个: 一、语法和学习难度 Python 语法简洁易懂:Python以其简洁、优雅的语法而闻名,代码的可读性很高。例如…

OceanBase 社区版 4.0 离线方式升级bp1至bp2 指南(含避坑总结)

注:目前社区版对 4.0 升级 bp1至 bp2也未有完善的文档,本次升级中也是遇到不少坑,写本文也希望对OB感兴趣的可以尝试少些遇坑。 也希望对升级有更好方式建议方式的朋友一起切磋交流,以便再进一步完善升级方案。 第一次做OB的升级&…

python学opencv|读取图像(六)读取图像像素RGB值

【1】引言 前序已经掌握了如何获取灰度图像的像素,文章链接为: python学opencv|读取图像(五)读取灰度图像像素-CSDN博客 实际上像素就像一个坐标轴,约束了图像的大小。 但实际上我们在学习过程中,对于同…

Linux kill、killall、pkill 命令区别

注:本文为 “Linux kill、killall、pkill” 相关几篇文章合辑。 未整理去重。 kill、killall、pkill、kill -9 区别 区别 进程 ID 唯一,所以 kill 一次只能杀死 1 个进程,其他相同名称的进程仍然存在,而 pkill 和 killall&#…

1139: Coin-row problem

解法&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e53; int dp[N]; int main() {int n;cin>>n;for (int i1;i<n;i) cin>>dp[i];for (int i2;i<n;i) {dp[i]max(dp[i-1],dp[i-2]dp[i]);}cout<<dp[n]<<endl;retur…

Ubuntu压缩打包解压

ubuntu压缩打包 上图&#xff0c;压缩当前目录svn 为svn.tar.gaz&#xff0c;解压后再当前解压目录生成svn文件 在Ubuntu中&#xff0c;你可以使用tar命令来创建一个压缩包&#xff0c;或者使用zip命令来创建一个.zip压缩文件。以下是两种常见的压缩方法&#xff1a; 下图&am…

Excel 合并工具 将文件复制到目标工作表中与操作日志记录

指定文件夹中读取符合条件的 Excel 文件&#xff0c;将其中的数据按照一定规则复制到目标工作表中&#xff0c;并进行相关的日志记录和工作簿保存操作。 先看下 excel 的结构 合并的结果 log 记录 vba 代码 Sub DeltaCheck()作者和创建时间的注释 定义工作表变量Dim ws As Wor…

Github----提交人不是自己

账号用户名都设置对的,但是提交人不是自己 解决 发现是用户名和账号都夹了"号导致 git config --global user.name "Your Name" git config --global user.email "your.emailexample.com"不用引号 git config --global user.name Your Name git …

ZZCMS2023存在跨站脚本漏洞(CNVD-2024-44822、CVE-2024-44818)

ZZCMS是一款用于搭建招商网站的CMS系统&#xff0c;由PHP语言开发&#xff0c;可快速搭建&#xff1a;医药招商、保健品招商、化妆品招商、农资招商、孕婴童招商、酒类副食类等招商网站。 国家信息安全漏洞共享平台于2024-11-14公布其存在跨站脚本漏洞。 漏洞编号&#xff1a…

[免费]SpringBoot+Vue企业OA自动化办公管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue企业OA自动化办公管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue企业OA自动化办公管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息技术在管理上越来越深入…

【MySQL】表的基本查询(下)

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

目前Java后端就业前景到底怎么样?

很多人都说今年对于IT行业根本没有所谓的“金三银四”“金九银十”。在各大招聘网站或者软件上不管是大厂还是中小公司大多都是挂个招聘需求&#xff0c;实际并不招人&#xff1b;在行业内的程序员基本都已经感受到了任老前段时间口中所谓的“寒气”。 虽然事实确实是如此&…

机器学习--张量

机器学习–张量 机器学习的数据结构–张量 张量是机器学习程序中的数字容器&#xff0c;本质上就是各种不同维度的数组&#xff0c;如下图所示。 张量的维度称为轴&#xff08;axis&#xff09;&#xff0c;轴的个数称为阶&#xff08;rank&#xff09; 标量–0D张量 impor…

3D 视觉定位技术:汽车零部件制造的智能变革引擎

在汽车零部件制造领域&#xff0c;传统工艺正面临着前所未有的挑战。市场对于零部件精度与生产效率近乎苛刻的要求&#xff0c;促使企业寻求突破之道。而 3D 视觉定位技术&#xff0c;为汽车零部件制造开启了精准定位与智能化生产的新纪元。 3D 视觉定位系统的核心技术原理 3…

uni-app之web-view组件 postMessage 通信【跨端开发系列】

&#x1f517; uniapp 跨端开发系列文章&#xff1a;&#x1f380;&#x1f380;&#x1f380; uni-app 组成和跨端原理 【跨端开发系列】 uni-app 各端差异注意事项 【跨端开发系列】uni-app 离线本地存储方案 【跨端开发系列】uni-app UI库、框架、组件选型指南 【跨端开…

数据结构 (37)外排序的基本方法

前言 外排序&#xff08;External Sorting&#xff09;是指处理那些无法完全加载到内存中的数据集时所使用的排序方法。由于数据量巨大&#xff0c;无法一次性全部放入内存&#xff0c;因此需要使用外部存储设备&#xff08;如磁盘&#xff09;来辅助排序过程。外排序的基本方法…

「Mac玩转仓颉内测版49」小学奥数篇12 - 图形变换与坐标计算

本篇将通过 Python 和 Cangjie 双语实现图形变换与坐标计算。这个题目帮助学生理解平面几何中的旋转、平移和对称变换&#xff0c;并学会用编程实现坐标变化。 关键词 小学奥数Python Cangjie图形变换坐标计算 一、题目描述 编写一个程序&#xff0c;模拟以下三种图形变换&a…

springboot系列--拦截器加载原理

一、拦截器加载原理 拦截器是在容器启动时&#xff0c;就创建并加载好&#xff0c;此时并未放入拦截器链中&#xff0c;只是放在一个拦截器集合当中&#xff0c;当一个请求进来之后&#xff0c;会通过匹配路径&#xff0c;查看是否有命中集合中的拦截器的拦截路径&#xff0c;如…