ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

redis进阶(一)Redis底层数据结构

2020-12-05 17:32:42  阅读:210  来源: 互联网

标签:进阶 SDS Redis redis 链表 哈希 字符串 节点


如大家众所周知,redis有string、list、hash、set、zset五种数据类型,但是大家对于每种数据类型的底层存储数据结构,可能还不是很清楚,在下面这篇文章中,主要讲述一下redis底层存储的7中数据类型。

1、简单动态字符串(SDS)(摘自redis设计与实现第二章)

  由于C语言字符串长度的不可修改性,redis实现了一种可变长度的字符串,即SDS,SDS的实现原理如下

 

  (1)len

  存储了字符串的长度

  由于SDS中存储了字符串,将获取字符串长度的时间复杂度从O(n)降到了O(1)

  (2)free

  存储了剩余可用的字符串长度

  (3)buf

  用于保存字符串

 

  减少内存分配次数

   (1)空间预分配:当用户修改字符串时,SDS API首先会检查空间是否满足需求,如果满足,则直接使用未使用的空间;如果不满足,则将空间扩展需要修改的内容大小,然后才执行修改操作

    空间预分配:修改后SDS小于1MB, 预留free=len;修改后SDS大于1MB,预留free=1MB;通过空间预分配操作,redis有效的减少了执行字符串增长所需要的内存分配次数。

   (2)惰性空间释放:当缩短SDS的存储内容时,并不会立即使用内存重分配来回收缩短操作后多出来的字节,而是用free将这些空间字节数量记录起来,并等待将来使用

    当需要真正释放内存时,调用API真正的释放内存。

  总结:

    (1)redis只会使用C字符串作为字面使用量,在大多数情况下,redis使用SDS(Simple Dynamic String,简单动态字符串)作为字符串标识。

    (2)比起C字符串,SDS具有一下优点:O(1)获取字符串长度;杜绝缓存区溢出;减少修改字符串长度,所需要的内存重分配次数;二进制安全;兼容部分C字符串函数

 

2、链表(摘自redis设计与实现第三章)

  每一个链表节点都是使用listNode实现,其中prev指向前几点,next指向后节点。

  

 

 

   在listNode基础上,redis又封装了一层list,使得链表的使用更加的高效。

  

 

 

 

  其中head保存了链表头结点,tail保存了链表尾节点,len保存了链表的节点数。dup、free和match实现多态链表所需的类型特定函数            

    • dup 函数用于复制链表节点所保存的值
    • free 函数用于释放链表节点所保存的值
    • match 函数用于链表中保存的值,是否与输入的一个值是否相等。

  下图为list和listNode组成的链表

  

 

 

 

  redis实现链表的特性可以总结如下

  • 双端:链表节点带有prev和next指针,获取某个节点的前置节点和后置节点的时间复杂度都是O(1)
  • 无环:表头节点和prev和表尾节点的next都指向null,对链表的访问以NULL为终点
  • 带表头指针和表尾指针:通过list结构的head和tail指针,使得获取头结点和尾节点的时间复杂度为O(1)
  • 带链表长度计数器:对链表节点数进行计数,使得获取链表节点数的时间复杂度为O(1)
  • 多态:链表节点使用void*指针来保存节点值,并使用list结构的dup、free、match三个属性为几点设置类型特定函数,所以链表可以保存各种不同类型的值。

3、字典

  redis的字典使用哈希表作为底层实现,一个哈希表里可以有多个哈希表节点,而每个哈希表节点就保存了字典中的一个键值对。一下主要介绍哈希表、哈希表节点、字典。

  哈希表

  

 

     其中:

    • table是一个数组,其中一个数组元素都是一个指向哈希表节点的指针,每一个哈希表节点都保存了一对键值对。
    • size记录了table的大小,也即是哈希表的大小
    • used记录了当前已使用节点的数量
    • sizemask=size-1 ,决定了一个键应该放tabl数组的哪个索引上

  哈希表节点

    结构定义如下图所示:

  

     其中:

    •   key保存键值对中的键,
    •   v保存这键值对中的值
    •   next为指向另一个哈希表几点的指针

  字典

  定义如下图所示:

  

 

   其中:

    • type标识dictType类型,privatedata是指向特定数据类型的数组;
    • ht包含了两个哈希表的数组,其中一个ht[0]保存哈希表,ht[1]只会在对ht[0]进行rehash时使用

  字典的整体实现如下图所示:

  

 

   字典还包括rehash和渐进式hash等要点,再这里就不讲述了

  总结

    • 字典被广泛应用于redis的各种功能,其中包括数据库和哈希键。
    • redis中的字典使用哈希表作为底层实现,每个字典带有两个哈希表,一个平时使用,一个在rehash时使用。
    • 当字典被用作数据库底层实现,或者哈希表底层实现时,redis使用muimuihash2算法计算哈希键的哈希值。
    • 哈希表使用链地址法解决键冲突,被分配到同一个索引上的多个键值对会连接成一个单项链表
    • rehash渐进式进程,并rehash到新的hash表中

4、跳跃表(待补充)

5、整数集合

  整数集合是集合键的底层实现之一,当一个集合只包含整数值,并且这个集合元素的数量并不多时,redis就会使用整数集合作为集合键的底层实现。

  其实现结构如下如所示:

  

  其中:encoding表示编码方式,可以为INTSET_ENC_INT16、INTSET_ENC_INT32、INTSET_ENC_INT64;length保存了元素数量,contents为实际的数组。

  总结:

    • 整数集合是集合键的底层实现之一
    • 整数集合的底层实现是数组,这个数组以有序、无重复的方式保存集合元素,在有需要的时候,程序会根据新添加元素的类型,改变这个数组的类型。
    • 升级操作为整数集合带来了操作上的灵活性,并且尽可能的节约了内存。
    • 整数集合只支持升级操作,不支持降级操作

 

 6、压缩列表(待补充)

 

标签:进阶,SDS,Redis,redis,链表,哈希,字符串,节点
来源: https://www.cnblogs.com/ttaylor/p/14081360.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有