Redis数据结构与对象——字典、跳跃表、整数集合、压缩列表、对象

Redis数据结构与对象——字典、跳跃表、整数集合、压缩列表、对象


仅作为笔记,除部分装载部分,码字不易,转载请标明出处。


前言

仅作为笔记


一、字典

1.1 字典的实现

  • 字典被广泛用于实现Redis的各种功能,包括数据库和哈希键。
  • Redis中的字典使用哈希表作为底层实现,每个字典带有两个哈希表,一个平时使用,一个仅在进行rehash时实现。

1.2 解决键冲突

  • Redis的哈希表使用链地址法解决哈希冲突(InnoDB中的哈希索引也是使用的这个)。

1.3 rehash

  • 负载因子:负载因子是在自动增加其哈希表容量之前允许哈希表获得的满度的度量。
  • 希表里写入的数据越来越多,哈希冲突可能也会越来越多,这就会导致某些哈希冲突链过长,进而导致这个链上的元素查找耗时长,效率降低。对于追求“快”的 Redis 来说,这是不太能接受的。所以,Redis 会对哈希表做 rehash 操作rehash 也就是增加现有的哈希桶数量,让逐渐增多的 entry 元素能在更多的桶之间分散保存,减少单个桶中的元素数量,从而减少单个桶中的冲突。那具体怎么做呢?其实,为了使 rehash 操作更高效,Redis 默认使用了两个全局哈希表:哈希表 1 和哈希表 2。一开始,当你刚插入数据时,默认使用哈希表 1,此时的哈希表 2 并没有被分配空间。随着数据逐步增多,Redis 开始执行 rehash,这个过程分为三步:
    1).给哈希表 2 分配更大的空间,例如是当前哈希表 1 大小的两倍;
    2).把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;
    3).释放哈希表 1 的空间。到此,我们就可以从哈希表 1 切换到哈希表 2,用增大的哈希表 2 保存更多数据,而原来的哈希表 1 留作下一次 rehash 扩容备用。

1.4 渐进式rehash

  • rehash这个过程看似简单,但是第二步涉及大量的数据拷贝,如果一次性把哈希表 1 中的数据都迁移完,会造成 Redis 线程阻塞,无法服务其他请求。此时,Redis 就无法快速访问数据了。为了避免这个问题,Redis 采用了渐进式 rehash。简单来说就是在第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。

1.5 重点回顾

  • 字典被广泛用于实现Redis的各种功能,包括数据库和哈希键。
  • Redis中的字典使用哈希表作为底层实现,每个字典带有两个哈希表,一个平时使用,一个仅在进行rehash时实现。
  • 当字典被用作数据库的底层实现,或者哈希键的底层实现时,Redis使用MurmurHash2算法来计算键的哈希值。
  • 哈希表使用链地址法来解决哈希冲突。
  • 哈希表进行扩展或者收缩时使用的时渐进式rehash,而不是一次性完成的。

二、跳跃表

跳跃表是比较基础和经典的数据结构,所以不过多赘述,在我之前的文章中对其进行过简单的总结(哈哈,其实是其他博主的优秀解析链接啦)。所以下面我还是简单说一下吧。

  • 是一种随机数据结构,实质就是一种可以进行二分查找的有序链表(按理说链表是不可以直接进行二分查找的)。
  • 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。随机二字是体现在提取索引的方法是随机的,之所以采用随机是因为希望提取索引是趋于均匀的(也就是并没有什么太死的规定,算是根据数学知识推理来的,有点玄学吧,有点深度学习炼丹的味道)
  • 那为什么是二分查找呢?因为提取索引是在前一层数量的一半空间复杂度为O(n),时间复杂度是O(logn),是使用空间换取时间来提升性能的操作。可以提取多层索引(都必须是前一层的一半),直至只有两个索引节点为止

2.1 重点总结

  • 跳跃表是有序集合的底层实现之一
  • Redis的跳表实现由zskiplist和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(表头结点、尾节点、长度),而zskiplistNode则用于表示跳跃节点。
  • 每个跳跃表节点的层高都是1至32之间的随机数。
  • 在同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的
  • 跳跃表中的节点按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序。

三、整数集合(数组)

比较简单,不过多赘述。

  • 集合键的底层实现之一,当一个集合只包含整数值元素,且这个集合的元素不多的时候,Redis使用整数集作为集合键的底层。
  • 整数集合是Redis用于保存整数值的抽象数据结构,是有序的,并且保证集合中无重复元素
  • 升级:虽然都是整数,但是长度有所不同,当新元素的类型比整数集合现有所有元素的类型都要长时,这个集合将进行升级,升级后将新元素添加。
  • 升级的好处:1)提升整数集合的灵活性,c作为静态语言,一般不会把不同类型的数据放在一个数据结构下,使用了自动升级技术可以保证这些不同类型的数据放在同样的数据结构下不出错误。2)尽可能的节约内存,自动升级的自动二字表明了在不需要升级时可以不用升级成更长的数据类型,这样可以节约内存

四、压缩列表

  • 压缩列表类似于一个数组,不同的是:压缩列表在表头有三个字段zlbytes,zltail和zllen分别表示长度,列表尾的偏移量和列表中的entry的个数,压缩列表尾部还有一个zlend,表示列表结束所以压缩列表定位第一个和最后一个是O(1),但其他就是O(n)是一种节约内存的顺序型数据结构是由一些列特殊编码的连续内存块组成的。
  • 被用作列表键和哈希键的底层实现之一
  • 压缩列表可以包含多个节点,每个节点可以保存一个字节数组或者整数值
  • 添加新节点到压缩列表,或者从压缩列表中删除节点,可能会引发连锁更行操作,但是几率不高。

五、对象

  • Redis数据库中的每个键值对的键和值都是一个对象,每当使用一对键值对就会创建两个对象。
  • Redis共有字符串、列表、哈希、集合、有序集合五种类型的对象,每种类型的对象至少有两种或以上的编码方式,不同的编码方式可以在不同的使用场景上优化对象的使用效率。
  • 检查一个键的类型实际上就是检查键的值对象的类型
  • Redis对象的回收机制是引用计数实现的回收机制,当一个对象不再被使用时,该对象所占的内存就会被自动释放。
  • Redis会共享值为0到9999的字符串对象
  • 对象会记录自己最后一次被访问的时间,这个时间可以用于计算对象的空转时间
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值