首页 > 数据库 >Redis数据结构8:REDIS_HASH

Redis数据结构8:REDIS_HASH

时间:2023-12-16 17:31:54浏览次数:25  
标签:rehash HASH 哈希 Redis REDIS key 操作 dictEntry

REDIS_HASH

Hash本质上就是一个保存若干键值对的数据结构,类似于Java中的HashMap。

同样的,hash中只能存在一个独一无二的key,所有的操作都围绕key展开。

hash的最大优点在于其可以提供最佳O(1)的查询时间复杂度。

通过一段原始数据key,通过特定算法将其哈希值转化为数组下标,通过相同的算法处理相同的值可以计算相同的索引,所以只需要O(1)时间复杂度就可以查询到key。

但有一片阴云一直笼罩在哈希表之上:哈希冲突

哈希冲突

前文提到,哈希表通过算法将key转化为下标,可以做到相同key,一定能有相同的下标值。

但key是无限的,下标值是有限的。无限对有限的映射,则必定有不同的key指向相同的下标,两个key抢占一个下标,就造成了哈希冲突

哈希冲突一般有多重解决方法,Redis采用链式哈希解决。

简单来说,链式哈希遇到哈希冲突,则将数组元素转化为一个链表,通过链表将冲突的元素连接起来。

在链表中,查询时间复杂度为O(n),这也是为什么要说hash最佳时间复杂度为O(1)。

结构设计

typedef struct dictht {
    // hash数组
    dictEntry **table;
    // hash大小
    unsigned long size;  
    // 大小掩码,用于计算索引值
    unsigned long sizemask;
    // 已有的节点数量
    unsigned long used;
} dictht;
typedef struct dictEntry {
    // 键值对中的键
    void *key;
  
    // 键值对中的值
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    // 指向下一个哈希表节点
    struct dictEntry *next;
} dictEntry;

在dictEntry的v中,是一个联合体union,里面存放一个指针,int和double。

这样的好处是如果值是一个整数或者小数,可以直接嵌入在dictEntry中而不需要指针。

rehash操作

typedef struct dict {
    …
    // 两个Hash表,交替使用,用于rehash操作
    dictht ht[2]; 
    …
} dict;

在正常服务请求阶段,插入的数据,都会写入到哈希表 1,此时的哈希表 2 并没有被分配空间。

随着数据逐步增多,触发了 rehash 操作,这个过程分为三步:

  • 给表 2 分配空间,一般会是表 1 的 2 倍;
  • 将表 1 的数据迁移到表 2 中;
  • 迁移完成后,释放表 1 的空间,并把表 2设置为表 1,然后在表 2 新创建一个空白的表,为下次 rehash 做准备。

但如果表 1 中数据量非常大,那么在迁移操作时会耗费大量计算资源,可能会阻塞Redis正常业务。

为了避免这种情况,Redis提出 渐进式哈希 作为解决方案。

渐进式哈希的核心是将数据迁移操作分步进行,而不是一口气完成。

在给表 2 分配空间后,每次哈希表的元素进行操作(增删改查)时,Redis会将被操作元素索引上的所有元素(因为可能是链表)迁移到表2上

随着操作越来越多,终有一刻表 1 能把所有数据都迁移到表 2 上,完成渐进式哈希操作。

何时处罚rehash

我们首先要明白一个概念:Load Factor(负载因子)。

负载因子 = 哈希表已存节点数 / 哈希表大小

以下两种条件满足一种,哈希表就会进行rehash操作:

  • 当负载因子大于等于 1 ,并且 Redis 没有执行 RDB 快照或没有进行 AOF 重写的时候,就会进行 rehash 操作。
  • 当负载因子大于等于 5 时,此时说明哈希冲突非常严重了,不管有没有有在执行 RDB 快照或 AOF 重写,都会强制进行 rehash 操作。

标签:rehash,HASH,哈希,Redis,REDIS,key,操作,dictEntry
From: https://blog.51cto.com/ErickRen/8853299

相关文章

  • Redis集群
    集群由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集。Redis集群是一个提供在多个Redis节点间共享数据的数据集Redis集群可以......
  • Docker部署Redis
    1、拉取redis镜像dockerpullredis2、创建redis配置文件mkdir-p/mydata/redis/conftouch/mydata/redis/conf/redis.conf3、启动redis镜像dockerrun-p6379:6379--nameredis\-v/mydata/redis/data:/data\-v/mydata/redis/conf/redis.conf:/etc/redis/redis.......
  • Redis远程字典服务
    1介绍Redis(RemoteDictionaryServer)是一个开源的内存数据存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据结构,包括字符串(strings)、哈希表(hashes)、列表(lists)、集合(sets)、有序集合(sortedsets)等。2使用场景相对于使用数据库,它读取更方便,时间更短相对于存储在硬盘上,它可......
  • Django-redis 常见错误
    Django-redis是一个Django缓存模块,用于连接Redis数据库。在使用Django-redis异步操作时,可能会遇到一些常见的错误。以下是一些可能出现的错误及其解决方法:Redis连接错误:原因:无法连接到Redis数据库。解决方法:检查Redis数据库是否已启动,并确保在Django设置中正确配置了......
  • Redis集群
    1.描述集群,即是RedisCluster。其由多个redis节点组成,redis数据保存在这些节点中。这些节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护,从节点只负责主节点数据和状态的复制。2.作用数据分区:redis集群是将数据分散存到多个节点中的。具体存到哪个节点是根绝数......
  • 哈希表(HashMap)与字符串哈希
    哈希表哈希表是一种通过映射来快速查找的数据结构。其通过键值对(key-value)来存储。一个数据通过哈希函数的运算来生成一个属于他自己的键值,尔后将其与键值绑定。当我们想查找这个数据时,就可以直接通过键来访问对应的值,时间复杂度近似为O(1)。哈希表适用于这样一种场景,当数据......
  • Redis基础命令操作
    一、基础命令1.ping(心跳检查)ping//输入ping命令,看到PONG响应,说明客户端与Redis的连接正常。 2.get/set(读写键值)setnamexiaoHong//setkeyvalue会将指定key-value写入到DB。getname//getkey则会读取指定key的value值。 3.select(切换数据库)sel......
  • docker部署redis主从集群
    1、创建数据目录(logs目录要给权限,要不然会报错)mkdir-pv/data/redis/(data,logs}chmod777/data/redis/logs2、redis.conf配置文件-—-主从配置master节点配置cd/data/redisvimredis.confport6379bind0.0.0.0daemonizenoprotected-modenorequirepass123......
  • Redis分布式锁的扩展方法
     分布式锁代码#region秒杀业务测试privatestaticreadonlystringredisConnectionStr="127.0.0.1:6379,connectTimeout=5000,allowAdmin=false,defaultDatabase=1";///<summary>///秒杀业务///</summary>priv......
  • redis
    开启redis进程  redis-serverredis.windows.confredis对字符串的常用命令set 设置   get 获取  del  删除mset   mget设置获取多个key/valincr  incrby  decr   decrby    加/减setnx   msetnx   设置新的key/val   key必须是原来不存......