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结构取而代之。
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表的数据结构为:
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 |