Redis Hash类型详解
Hash类型常用命令
想学习全部的命令大家可以去Redis官网,这里面有最权威最官方的说明(redis.io/commands#ha…
创建一个Hash类型,直接使用HSET key field value [field value ...]就可以了,返回值类型为整数
还有一个功能一样的命令,HMSET key field value [field value ...] 返回值类型为字符串类型!
取key中某个filed对应的值,用HGET key field
一次性取key中多个field对应的值,用HMGET key field [field ..]
一次性获取全部的field的值用HKEYS key
返回对应key中键值对的个数,用 HLEN key
判断当前key中是否含有某个field,可以用HEXISTS,存在则返回1,不存在则返回0
返回key中全部field和value信息,用HGETALL命令
返回key中某个field对应的value的长度,用HSTRLEN命令
返回key中全部value的信息,用HVALS命令
删除key中对应的field和value,用HDEL命令
HSETNX命令与String中的SETNX命令功能差不多,设置key中对应的field和value,如果key中不存在这个field,则成功,若已经存在则失败(注意这里判断是否存在的是field而不是key本身)
HINCRBY对value进行自增操作,这里一定要指定步长
也可以指定步长为浮点数类型,但是需要用HINCRBYFLOAT命令
好了,以上就是官网中给出的hash类型的全部命令了(除了HSCAN),相信大家已经对Hash有了一个初步了解,下面我们一起深入了解Hash的数据结构和机制吧
类型
哈希表数据结构
Hash类型是Redis中非常重要的复合型结构,通过(K,V)来实现,采用链地址法来处理哈希冲突,整体数据结构与Java中的HashMap极为相似,都是采用数组+链表(Redis中不会将链表改为红黑树)的结构来实现,我们直接来看一下哈希表结构图
图片来源blog.csdn.net/codejas/art…
我们来一起看一下最左边dictht中的字段
- table:指向哈希表的指针
- size:哈希表数组的大小
- sizemask:用于计算哈希值的掩码
- used:已经存储的(K,V)个数
Hash类型完整结构
Hash类型的完整结构如下
图片来源blog.csdn.net/codejas/art…
字典类型的中其实包含两个哈希表,一个是我们刚刚讲到用于存储(K,V)的哈希表ht[0],而另外一个ht[1]用于后续的扩容。
Rehash机制
字典类型容量变化过程叫做rehash,需要满足一定的条件才能触发扩容机制
- 服务器当前没有进行BGWRITEAOF或者BGSAVE命令,且当前键值对个数超过一维数组的大小(这两个命令是用于Redis持久化的,挖个坑,改天给你们发一篇Redis持久化的)
- 如果当前键值对个数超过一维数组大小的五倍,无论是否在进行BGWRITEAOF或者BGSAVE命令,都会强制扩容。
Hash类型扩容后数组的长度为原来的二倍
缩容机制:如果当前键值对个数少于一维数组大小的十分之一,则触发缩容过程。缩容不会考虑当前服务器是否在进行BGWRITEAOF或者BGSAVE命令
渐进式Rehash
当触发扩容的时候,Redis会首先为ht[1] 分配一块内存空间。如果当前字典是一个比较大的字典,那么整个扩容过程的时间复杂度为O(n),直接完整进行扩容机制可能会导致Redis一段时间内停止服务。为了避免停止服务的情况,Redis的设计团队采用了渐进式rehash的策略,每次只对原哈希表中的一小部分进行搬迁,这样渐进式的进行,直到全部键值对都迁移到新的哈希表中。
看到这里你可能会问,如果搬迁的过程中我们需要查询键值会怎么办?别急,这个问题我们一步一步来看
首先,对于key的查询,我们需要到原来的哈希表中进行查找,如果找到对应的value,直接返回就可以了。如果没有找到,那么只有两种可能,一个是这个键值对已经搬迁到新的哈希表了,另外一种可能是根本就不存在这个键值对,无论是哪种可能,我们都需要再去新哈希表中对他进行查找,如果找到了就返回,如果找不到说明这个键值对不存在。
用上面的图片来举个例子,假设原来(k1,v1),(k2,v2),(k3,v3)都挂在数组下标为0的位置,在扩容时,我们采用渐进式搬迁的策略,此时(k1,v1),(k2,v2)已经完成搬迁。如果此时客户端发出了查询k4的请求,我们会先在oldHashTable中进行查询,如果查询到则返回,如果查询不到就去newHashTable中查询,显然我们无法在oldHashTable中查询到k4对应的值,所以我们再去newHashTable中进行查询,如果这次也没有查到说明不存在k4以及对应的值
可能还有人会问,如果现在要添加一个键值对呢?添加KV的操作可以直接到新哈希表中进行添加,不用考虑原来旧的哈希表
字典类型的另外一种实现
其实字典类型除了上面说的哈希表结构,还存在一种ziplist(压缩列表)的结构,不过这种结构只适用于键值对较少的情况下。
可以看到,当前test中只包含一个键值对,此时整个字典使用压缩列表来实现的。压缩列表会在内存中申请一块连续的内存空间
在这种情况下查找元素的时间复杂度为O(n),并不适合存储大量键值对。使用ziplist作为哈希表的条件如下:
- 哈希对象保存的所有键值对的键和值的字符串长度都小于
64字节; - 哈希对象保存的键值对数量小于
512个;
如果不满足上述两个条件,则自动转换为hashtable类型
总结
Hash类型是Redis中一个非常重要的数据结构,在平时开发中我们可以将对象转为Hash类型进行存储。其实整个Redis就是一个大的Hash类型,所有的数据结构都是通过K-V的结构来进行定位。
好了,终于又水了一期,上一篇String类型的阅读量有点低,不知道大家想看什么内容呢。大家有想看的都可以后台给我留言,我会尽力给大家做的,后续Redis还会出三篇基础数据结构、持久化、集群、内存回收和一些常见的面试题,Redis写完就开始更MySQL,希望大家可以多多关注。
我是星海,与你一起看遍世间的Code,欢迎关注我的微信公众号
《Redis深度历险》