目录
redis hash相关命令的简单实用
redis hash菜鸟教程:Redis 哈希(Hash) | 菜鸟教程
参考学习: 哈希表 — Redis 设计与实现
HSET key field value
将哈希表 key 中的字段 field 的值设为 value 。
HGET key field
获取存储在哈希表中指定字段的值/td>
HKEYS key
获取所有哈希表中的字段
HLEN key
获取哈希表中字段的数量
HGETALL key
获取在哈希表中指定 key 的所有字段和值
HVALS key
获取哈希表中所有值
HMGET key field1 [field2]
获取所有给定字段的值
HMSET key field1 value1 [field2 value2 ]
同时将多个 field-value (域-值)对设置到哈希表 key 中。
HEXISTS key field
查看哈希表 key 中,指定的字段是否存在。
HSETNX key field value
只有在字段 field 不存在时,设置哈希表字段的值。
hash结构的底层实现
Redis中的哈希采用了典型的拉链法解决冲突的方式,当有多个key-value
键值对的键名key
映射值相同时,系统会将这些键值value
以单链表的形式保存,同时为了控制哈希表占用内存大小,Redis采用了双哈希表ht[2]
结构,并逐步扩大哈希表容量的策略
通常情况下只有一个 hashtable 是有值的;在 dict 扩容缩容时,需要分配新的 hashtable,然后进行渐进式搬迁,这时候两个 hashtable 存储的分别是旧的 hashtable 和新的 hashtable。待搬迁结束后,旧的 hashtable 被删除,新的 hashtable 取而代之;当 hash 表因为元素的逐渐删除变得越来越稀疏时,,Redis 会对 hash 表进行缩容来减少 hash 表的第一维数组空间占用。缩容的条件是元素个数低于数组长度的 10%。
收缩或者扩展哈希表需要将ht[0]表中的所有键全部rehash到ht[1]中,但是rehash操作不是一次性、集中式完成的,而是分多次,渐进式,断续进行的,这样才不会对服务器性能造成影响。
扩容机制过程中的操作
扩容条件
- 负载因子超过设定阈值时,触发扩容(rehash)。具体来说,当字典中的元素数量超过了字典容量的负载因子时,Redis 会自动扩容哈希表。
- 默认负载因子:Redis 默认的负载因子为 1,Redis 会将哈希表容量扩大为原来的 2 倍。
- 扩容的目的:为了解决哈希冲突,提高哈希表的查找效率。
扩容过程
1. 计算大小
- 当负载因子小于设定阈值时,Redis 会创建一个新的哈希表(
ht[1]
),其大小为当前哈希表的键值对数量所能容纳的最小 2 的幂次方。 - 如果
ht[0].used
(当前元素数量)为N
,则新的字典大小为不小于N
的 2 的幂次方。
2. 渐进式 rehash
- 每当执行哈希表的操作时(如
SET
、GET
、DEL
等),Redis 会检查是否有待迁移的元素。如果有迁移任务,Redis 会将部分元素从旧哈希表(ht[0]
)迁移到新哈希表(ht[1]
)。 - 迁移操作会在每次操作中分批进行,直到所有元素都迁移完成,避免一次性迁移带来的性能压力。
3. 完成 rehash 后
- 当所有的元素迁移到新哈希表后,Redis 会释放旧哈希表所占用的内存。
- 此时,
ht[0]
被置为空表,ht[1]
成为新的哈希表。
键的访问处理
在扩容过程中,对键的访问处理主要包括:
-
查找键:当客户端尝试查找或修改一个键时,Redis首先根据旧的哈希函数计算键应该位于哪个哈希桶。如果正在进行扩容,那么这个键可能已经被移动到了新的哈希表中。在这种情况下,Redis会根据当前的哈希表状态(是新表还是旧表)来决定使用哪个表的索引来查找键。
-
写入键:当写入新的键值对时,Redis会根据当前的哈希表状态(是否正在进行扩容)来决定应该将键值对写入到哪个表中。在扩容过程中,新写入的键值对通常会被写入到新的哈希表中。