Redis底层数据结构是什么?

问题:redis为什么这么快?

1、redis是内存数据库,所有的操作都在内存上完成;(内存的访问速度本身就很快)
2、归功于redis的数据结构

Redis键值对中的数据类型:String、List、Hash、Set(集合)、Sorted Set(有序集合);

底层数据结构(6种):简单动态字符串、双向链表、压缩列表、哈希表、跳表、整数数组

注意:数据类型是指数据的保存形式,而数据结构是指它们的底层实现,注意区分!

与数据类型的关系图如下:
图1

问题:这些数据结构都是值的底层实现,那么键和值本身之间用什么结构组织?

Redis使用了一个全局哈希表保存所有的键值对;
一个哈希表,其实就是一个数组,数组的每个元素称为一个哈希桶;每个哈希桶中保存了键值对数据;

问题:如果值是集合类型,作为数组元素的哈希桶怎么保存?

哈希桶中的元素保存的并不是值本身,而是指向具体值的指针。如下图所示,即使值是一个集合,也可以通过*value指针被查找到:

图2

哈希表的好处:
用O(1)的时间复杂度来快速查找到键值对——我们只需要计算键的哈希值,就可以知道它对应的哈希桶的位置,然后就可以访问相应的entry元素;

潜在风险:往redis中写入大量数据后,可能会发现操作变慢了?

原因:哈希表的冲突问题和rehash可能带来的操作阻塞;

1、哈希冲突:两个key的哈希值和哈希桶计算对应关系时,正好落在了同一个桶中;

  • redis解决哈希冲突的方式: 链式哈希(指同一个哈希桶中的多个元素用一个链表来保存,他们之间依次用指针连接)

如下图所示,这也就形成了一个链表,也叫做哈希冲突链:

图三

  • 由于哈希冲突链上的元素只能通过指针逐一查找再操作,如果哈希表数据越来越多,哈希冲突也会越来越多,这就导致哈希冲突链过长,进而导致这个链上的元素查找耗时长,效率降低;所以redis会对哈希表做rehash操作。

2、rehash:即增加现有哈希桶的数量,让逐渐增多的entry元素能在更多的桶之间分散保存,减少单个桶中的元素数量,从而减少单个桶中的冲突;

具体怎么做:
redis默认使用了两个全局哈希表:哈希表1和哈希表2;
当你刚插入数据时,默认使用哈希表1,此时哈希表2并没有被分配空间,随着数据逐步增多,redis开始执行rehash

  1. 给哈希表2分配更大的空间;
  2. 把哈希表1中的数据重新映射并拷贝到哈希表2中;
  3. 释放哈希表1的空间;

原来的哈希表1留作下一次rehash扩容备用。

风险:第二步中,如果一次性拷贝大量数据到哈希表2中,会造成redis线程阻塞,无法服务其他请求。

解决:redis采用渐进式rehash;

渐进式rehash:在第二步拷贝数据时,redis仍然正常处理客户端请求,每处理一个请求时,从哈希表1的第一个索引位置开始,顺带将这个索引位置上的所有entries拷贝到哈希表2中;等处理下一个请求时,再顺带拷贝哈希表1中的下一个索引位置的entries。

如下图所示:

在这里插入图片描述

渐进式rehash执行时,redis本身还会有一个定时任务在执行rehash,如果没有键值对操作时,这个定时任务会周期性的搬移一些数据到新的哈希表中,这样可以缩短整个rehash的过程;

这样就巧妙的把一次性大量拷贝的开销,分摊到了多次处理请求的过程中,避免了耗时操作,保证了数据的快速访问;

注:文章是总结了极客时间上《redis核心技术与实战》数据结构的一文;仅用于学习,非商业用途!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值