42张图,带你真正搞懂redis数据类型的底层( 六 )


我想了一下:按照前文所讲的内容,应该是4 。但是,假如是4,存在和收缩后的长度相等,是不是又该扩容?
假如收缩后 长度为4
,不仅不会收缩,甚至还会
报错

我们回过头来再看看设定:题目可能成立吗?哈希表的扩容都是 2倍增长的,最小是4,4 ===》 8 ====》 16 =====》 32 ======》 64 ====》 128

也就是说:不存在长度为 40多的情况,只能是64 。但是如果是64的话,64 X 0.1(收缩界限)= 6.4,也就是说在减少到6的时候,哈希表就会收缩,会缩小到多少呢?是8 。此时,再继续减少到4,也不会再收缩了 。所以,根本不存在一个长度大于40,但是存在的元素为4的哈希表的 。

扩容步骤

42张图,带你真正搞懂redis数据类型的底层

文章插图
 
收缩步骤
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
渐进式refresh在"扩容步骤"和"收缩步骤" 两幅动图中每幅图的 第四步骤 “将ht[0]中的数据利用哈希函数 重新计算,rehash到ht[1]”,并不是一步完成的,而是分成N多步,循序渐进地完成的 。因为hash中有可能存放几千万甚至上亿个key,毕竟Redis中每个 hash中可以存 2^32-1 键值对 (40多亿),假如一次性将这些键值rehash的话,可能会导致服务器在一段时间内停止服务,毕竟哈希函数就得 计算一阵子呢 (对吧(#^.^#)) 。
哈希表的refresh是分多次、渐进式进行的 。渐进式refresh和下图中左边橘黄色的“统筹”部分中的rehashidx密切相关:
  • rehashidx 的数值就是现在rehash的 元素位置
  • rehashidx 等于-1的时候说明没有在进行refresh
甚至在进行期间,每次对哈希表的增删改查操作,除了正常执行之外,还会顺带将ht[0]哈希表相关键值对 rehash 到ht[1] 。
以扩容步骤 举例 :
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
intset整数集合是 集合键 的底层实现方式之一 。
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
跳表跳表这种数据结构长这样:
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
redis中把跳表抽象成如下所示:
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
看这个图,左边“统筹”,右边实现 。
统筹部分 有几点要说:
  • header: 跳表表头
  • tail:跳表表尾
  • level:层数最大的那个节点的层数
  • length:跳表的长度
实现部分有以下几点说:
  • 表头:是链表的哨兵节点,不记录主体数据 。是个 双向链表分值 是有顺序的
  • o1、o2、o3是节点所保存的成员,是一个指针,可以指向一个SDS值 。
  • 层级高度最高是32 。没每次创建一个新的节点的时候,程序都会 随机生成 一个介于1和32之间的值作为level 数组的大小,这个大小就是“高度”
redis五种数据结构的实现redis对象redis中并没有 直接使用 以上所说的那种数据结构来实现键值数据库,而是基于一种对象,对象底层再 间接的引用 上文所说的 具体 的数据结构 。
就像这样:
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
字符串
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
其中:embstr和raw都是由 SDS动态字符串 构成的 。唯一区别是: raw 是分配内存的时候,redis object和sds各分配一块内存,而embstr是redisobject和raw 在一块儿内存 中 。
列表
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
列表
hash
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
哈希
set
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
set
set
42张图,带你真正搞懂redis数据类型的底层

文章插图
 
zset
跳跃表是一种 有序 数据结构,它通过在 每个节点 中维持 多个指向其它节点 的指针,从而达到快速访问节点的目的 。具有如下 性质 :
1、由很多层结构组成;


推荐阅读