redis 底层做了些什么之Hash

·  阅读 293

系列文章:

redis 底层做了些什么之简单动态字符串SDS

redis 底层做了些什么之List

redis 底层做了些什么之Hash

Redis的值是Hash类型(又可以称为字典Dict)底层采用哈希表实现,一个哈希表有多个哈希表节点,每个 哈希表节点就保存了一个键值对

哈希表的结构:

一个大小为4的空哈希表结构,如下图所示

table是一个数组,数组中每个元素都指向一个哈希表节点

size属性记录了哈希表的大小,也就是table数组的大小

sizemask属性的值总是等于size-1,这个属性和哈希值一起决定一个键应该被放到table数组的哪个索引上面

used属性记录了table数组中非null的数目,非null即指针已经对应了一个哈希表节点

哈希节点结构:

用dictEntry表示,每个dictEntry结构保存着一个键值对

K属性保存键

V属性保存值,值可以是一个指针,或者是数值

next属性是指向另一个哈希表节点的指针,利用指针可以将多个哈希值相同的键值对连接在一起,以此解决了键冲突的问题 Redis 中采用字典dict又对哈希表进行了一层包装,dict的结构如下 type属性是一个指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数.

privdata属性保存了需要传给那些类型特定函数的可选参数

ht属性是一个包含两个项的数组,正常情况下,字典只使用ht[0]哈希表,当哈希表在rehash的时候,会使用ht[1]哈希表.

rehashidx记录了rehash的进度,如果目前没有rehash,它的值为-1

哈希算法:

当一个新的键值对被添加到字典里时,需要根据键值对的键计算出哈希值和table数组的索引值,根据索引值,将键值对添加到数组的指定位置上.

1.利用字典设置的hash函数,计算key的哈希值

2.索引值 = 哈希值 & sizemask (二进制作与运算)

rehash操作:

随着不断添加或删除键值对,为了让哈希表的负载因子维持在一个合理的范围内,需要对哈希表进行rehash操作(利用ht[1]的哈希表)

1.为字典ht[1]哈希表分配空间,空间的大小取决于是扩展还是收缩,以及ht[0]当前包含的键值对数量(即ht[0].used属性的值)

(1) 如果要扩展哈希表,首先计算 x = ht[0].used*2的值,然后找到第一个大于等于x的 2的n次方的值y , y就是ht[1]应该分配的空间大小.

例如 x = 5*2, 那么y 应该是2的4次方 = 16 是第一个大于等于x的2的n次方,所以y = 16,.
复制代码

(2) 如果是缩减哈希表 x = ht[0].used , 然后找到第一个大于等于x的 2的n次方的值y , y就是ht[1]应该分配的空间大小.

例如 x = 5 , 那么y 应该是2的3次方 = 8 是第一个大于等于x的2的n次方,所以y = 8
复制代码

2.将ht[0]中所有键值对重新计算索引,放到ht[1]哈希表的指定位置上

3.当ht[0]所有键值对迁移到ht[1]的工作完成后(ht[0]变成空表),释放ht[0],将ht[1]设置为ht[0],并为ht[1]创建一个空白哈希表,为下一次rehash作准备.

Hash常用语法简介:

HSET

往字典中添加键值对 一个字典可以添加一个键值对,也可以是多个

语法:

HSET key field value
复制代码

HGET

获取字典中某个键(key) 对应的value

语法:

HGET key field
复制代码

HMGET

获取字典中多个键(key1 key2 …) 对应的多个value

语法:

HMGET key field [field ...]
复制代码

HGETALL

得到字典中所有的键值对

语法:

HGETALL key
复制代码

HLEN

获得字典中所有键值对的数目

语法:

HLEN key
复制代码

HEXISTS

判断某个字典的所有key中是否包含某个值

语法:

HEXISTS key field
复制代码

HKEYS

显示字典中所有key值

语法:

HKEYS key
复制代码

HVALS

显示字典中的所有value值

语法:

HVALS key
复制代码

分类:
后端
标签: