温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Redis字典知识点有哪些

发布时间:2021-12-27 16:44:38 来源:亿速云 阅读:119 作者:iii 栏目:大数据

这篇文章主要讲解了“Redis字典知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis字典知识点有哪些”吧!

字典数据结构

说起字典,也许大家比较陌生,但是我们都知道 Redis 本身提供 KV 查询的方式,这个 KV 就是其实通过底层就是通过字典保存。

另外,Redis 支持多种数据类型,其中一种类型为 Hash 键,也可以用来存储 KV 数据。

阿粉刚开始了解的这个数据结构的时候,本来以为这个就是使用字典实现。其实并不是这样的,初始创建 Hash 键,默认使用另外一种数据结构-「ZIPLIST」(压缩列表),以此节省内存空间。

不过一旦以下任何条件被满足,Hash 键的数据结构将会变为字典,加快查询速度。

  • 哈希表中某个键或某个值的长度大于 server.hash_max_ziplist_value (默认值为 64 )。
  • 压缩列表中的节点数量大于 server.hash_max_ziplist_entries (默认值为 512 )。

Redis 字典新建时默认将会创建一个哈希表数组,保存两个哈希表。

其中 ht[0] 哈希表在第一次往字典中添加键值时分配内存空间,而另一个 ht[1] 将会在下文中扩容/缩容才会进行空间分配。

Redis字典知识点有哪些

字典中哈希表其实就等同于Java HashMap,我们知道 Java 采用数组加链表/红黑树的实现方式,其实哈希表也是使用类似的数据结构。

哈希表结构如下所示:

Redis字典知识点有哪些

其中 table 属性是个数组, 其中数组元素保存一种 dictEntry 的结构,这个结构完全类似与 HashMap 中的  Entry 类型,这个结构存储一个 KV 键值对。

同时,为了解决 hash 碰撞的问题,dictEntry 存在一个 next 指针,指向下一个dictEntry ,这样就形成  dictEntry  的链表。

Redis字典知识点有哪些

现在,我们回头对比 Java 中 HashMap,可以发现两者数据结构基本一致。

只不过 HashMap 为了解决链表过长问题导致查询变慢,JDK1.8 时在链表元素过多时采用红黑树的数据结构。

下面我们开始添加新元素,了解这其中的原理。

元素增加过程

当我们往一个新字典中添加元素,默认将会为字典中 ht[0] 哈希表分配空间,默认情况下哈希表 table 数组大小为 4(「DICT_HT_INITIAL_SIZE」)。

新添加元素的键值将会经过哈希算法,确定哈希表数组的位置,然后添加到相应的位置,如图所示:

Redis字典知识点有哪些

继续增加元素,此时如果两个不同键经过哈希算法产生相同的哈希值,这样就发生了哈希碰撞。

假设现在我们哈希表中拥有是三个元素,:

Redis字典知识点有哪些

我们再增加一个新元素,如果此时刚好在数组 3 号位置上发生碰撞,此时 Redis 将会采用链表的方式解决哈希碰撞。

Redis字典知识点有哪些

「注意,新元素将会放在链表头结点,这么做目的是因为新增加的元素,很大概率上会被再次访问,放在头结点增加访问速度。」

这里我们在对比一下元素添加过程,可以发现 Redis 流程其实与 JDK 1.7 版本的 HashMap 类似。

当我们元素增加越来越多时,哈希碰撞情况将会越来越频繁,这就会导致链表长度过长,极端情况下 O(1) 查询效率退化成 O(N) 的查询效率。

为此,字典必须进行扩容,这样就会使触发字典 rehash 操作。

扩容

当 Redis 进行 Rehash 扩容操作,首先将会为字典没有用到 ht[1] 哈希表分配更大空间。

Redis字典知识点有哪些
❝    

画外音:ht[1]  哈希表大小为第一个大于等于 ht[0].used*2 的 2^2(2的n 次方幂)

然后再将 ht[0] 中所有键值对都迁移到 ht[1] 中。

Redis字典知识点有哪些    
简单起见,忽略指向空节点

当节点全部迁移完毕,将会释放 ht[0]占用空间,并将 ht[1] 设置为 ht[0]

Redis字典知识点有哪些    

   

扩容 操作需要将 ht[0]所有键值对都 Rehashht[1] 中,如果键值过多,假设存在十亿个键值对,这样一次性的迁移,势必导致服务器会在一段时间内停止服务。

另外如果每次 rehash 都会阻塞当前操作,这样对于客户端处理非常不友好。

为了避免 rehash对服务器的影响,Redis 采用渐进式的迁移方式,慢慢将数据迁移分散到多个操作步骤。

这个操作依赖字典中一个属性 rehashidx,这是一个索引位置计数器,记录下一个哈希表 table 数组上元素,默认情况为值为 「-1」

假设此时扩容前字典如图所示:

Redis字典知识点有哪些

当开始 rehash 操作,rehashidx将会被设置为 「0」

这个期间每次收到增加,删除,查找,更新命令,除了这些命令将会被执行以外,还会顺带将 ht[0]哈希表在 rehashidx 位置的元素 rehash 到 ht[1] 中。

假设此时收到一个 「K3」 键的查询操作,Redis 首先执行查询操作,接着 Redis 将会为 ht[0]哈希表上table 数组第 rehashidx索引上所有节点都迁移到 ht[1] 中。

Redis字典知识点有哪些

当操作完成之后,再将 rehashidx 属性值加 1。

最后当所有键值对都 rehashht[1]中时,rehashidx将会被重新设置为 -1。

虽然渐进式的 rehash 操作减少了工作量,但是却带来键值操作的复杂度。

这是因为在渐进式 rehash 操作期间,Redis 无法明确知道键到底在 ht[0]中,还是在 ht[1] 中,所以这个时候 Redis 不得不查找两个哈希表。

以查找为例,Redis 首先查询 ht[0] ,如果没找到将会继续查找 ht[1],除了查询以外,更新,删除也会执行如上的操作。

添加操作其实就没这么麻烦,因为ht[0]不会在使用,那就统一都添加到 ht[1] 中就好了。

最后我们再对比一下 Java HashMap 扩容操作,它是一个一次性操作,每次扩容需要将所有键值对都迁移到新的数组中,所以如果数据量很大,消耗时间就会久。

感谢各位的阅读,以上就是“Redis字典知识点有哪些”的内容了,经过本文的学习后,相信大家对Redis字典知识点有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI