1、说明

Redis的字典相当于Java语言里面的HashMap,它是无序的字典,内部存储了很多的键值对。Redis字典的值只能是字符串,同时为了追求高性能,Redis采用了渐进式rehash策略。

当hash移除了最后一个元素之后,该数据结构被自动删除,内存被回收。

Redis的每个hash可以存储 232 - 1键值对(40多亿)。

2、内部实现

2.1 rehash策略

redis采用的是渐进式rehash策略。redis会在rehash的同时,保留新旧两个hash结构,查询时会同时查询两个结构,然后在后续的定时任务以及hash操作指令中,循序渐进的将旧hash的内容一点点的迁移到新的hash结构中,当迁移完成了,就会使用新的hash结构取而代之。

redis hash结构修改 redis hash结构原理_redis hash结构修改

 2.2 hash表结构

redis的hash表结构和java的HashMap几乎是一致的,都是采用“数组+链表”的数据结构,第一维是数组,第二维是链表,然后将数据映射到数组中的某个位置,通过数组下标访问元素以提高数据的查询速度。

2.2.1 映射方式

hash表是如何将数据映射到数组上的?比如,现申请一个长度为4的数组,将每个数的值对数组长度4取模,然后放置到对应的数组槽位中,这样就把离散的数据映射到了连续的空间,所以hash表也称为散列表。但这时会存在一个问题,比如有4个数为6,7,8,11,那么7和11对4取模的结果都是3,所以他们会占据同一个槽位,这种情况也就称为冲突。

2.2.2 链地址法

Redis中解决冲突采用的是链地址法,也就是将有冲突的数据用一个链表串联起来,这样只需对存储结构稍加变化,就可以解决冲突了。hash表的数据结构为:

redis hash结构修改 redis hash结构原理_redis_02

hash表的插入和删除都依赖于查找,必须先把元素找到,才可以对数据结构进行修改操作。根据上面的数据结构可以看出,hash表的元素在第二维的链表上,所以也是先取模定位到元素在数组上的位置,然后再继续进行查找。

正常情况下,hash表中的元素个数等于第一维数组的长度时,就会进行扩容,扩容的新数组是原数组大小的2倍。

当hash表中的元素逐渐被删除变得稀疏时,即元素个数低于数组长度的10%时,redis会对hash表进行缩容。

3、操作指令

命令

描述

HSET key field value

将哈希表key中的字段field的值设置为value

HSETNX key field value 

只有字段field不存在时,才设置哈希表字段的值

HMSET key field1 value1

[field2 value2]

同时将多个键值对设置到hash表中

HGET key field

获取存储在hash表中指定字段的值

HMGET key field1 [field2]

获取所有给定字段的值

HGETALL key  

获取hash表中所有的键值对信息

HEXISTS key field

检测hash表key中指定的字段field是否存在

HDEL key field1 [field2]

删除hash表key中一个或多个指定的字段

HINCRBY key field increment 

将hash表key中的指定字段field的整数值加上增量increment

HINCRBYFLOAT key field increment 

将hash表key中的指定字段field的浮点数加上增量increment

HLEN key

获取hash表中字段的数量

HKEYS key

获取hash表中所有的字段

HVALS key

获取hash表中所有的值

HSCAN key cursor [MATCH pattern] [COUNT count]  

迭代hash表中的键值对。当数据量较大时,使用scan来迭代遍历,而不是使用hkeys