Redis有五种基本数据结构:字符串、hash、set、zset、list。但是你知道构成这五种结构的底层数据结构是怎样的吗? 今天我们来花费五分钟的时间了解一下。 (目前redis版本为3.0.6)

动态字符串SDS

SDS是"simple dynamic string"的缩写。 redis中所有场景中出现的字符串,基本都是由SDS来实现的

  • 所有非数字的key。例如set msg "hello world" 中的key msg.
  • 字符串数据类型的值。例如`` set msg "hello world"中的msg的值"hello wolrd"
  • 非字符串数据类型中的“字符串值”。例如RPUSH fruits "apple" "banana" "cherry"中的"apple" "banana" "cherry"

SDS长这样:

free:还剩多少空间 len:字符串长度 buf:存放的字符数组

空间预分配

为减少修改字符串带来的内存重分配次数,sds采用了“一次管够”的策略:

  • 若修改之后sds长度小于1MB,则多分配现有len长度的空间
  • 若修改之后sds长度大于等于1MB,则扩充除了满足修改之后的长度外,额外多1MB空间

惰性空间释放

为避免缩短字符串时候的内存重分配操作,sds在数据减少时,并不立刻释放空间。

int

就是redis中存放的各种数字 包括一下这种,故意加引号“”的

双向链表

长这样:

分两部分,一部分是“统筹部分”:橘黄色,一部分是“具体实施方“:蓝色。主体”统筹部分“:

  • head指向具体双向链表的头
  • tail指向具体双向链表的尾
  • len双向链表的长度

具体"实施方":一目了然的双向链表结构,有前驱pre有后继next。由listlistNode两个数据结构构成。

ziplist

压缩列表。 redis的列表键和哈希键的底层实现之一。此数据结构是为了节约内存而开发的。和各种语言的数组类似,它是由连续的内存块组成的,这样一来,由于内存是连续的,就减少了很多内存碎片和指针的内存占用,进而节约了内存。

然后文中的entry的结构是这样的:

元素的遍历

先找到列表尾部元素:

然后再根据ziplist节点元素中的previous_entry_length属性,来逐个遍历:

连锁更新

再次看看entry元素的结构,有一个previous_entry_length字段,他的长度要么都是1个字节,要么都是5个字节:

  • 前一节点的长度小于254字节,则previous_entry_length长度为1字节
  • 前一节点的长度大于254字节,则previous_entry_length长度为5字节

假设现在存在一组压缩列表,长度都在250字节至253字节之间,突然新增一新节点new, 长度大于等于254字节,会出现:

程序需要不断的对压缩列表进行空间重分配工作,直到结束。除了增加操作,删除操作也有可能带来“连锁更新”。 请看下图,ziplist中所有entry节点的长度都在250字节至253字节之间,big节点长度大于254字节,small节点小于254字节。

哈希表

哈希表略微有点复杂。哈希表的制作方法一般有两种,一种是:开放寻址法,一种是拉链法。redis的哈希表的制作使用的是拉链法。整体结构如下图:

也是分为两部分:左边橘黄色部分和右边蓝色部分,同样,也是”统筹“和”实施“的关系。 具体哈希表的实现,都是在蓝色部分实现的。 先来看看蓝色部分:

这也分为左右两边“统筹”和“实施”的两部分。右边部分很容易理解:就是通常拉链表实现的哈希表的样式;数组就是bucket,一般不同的key首先会定位到不同的bucket,若key重复,就用链表把冲突的key串起来。

新建key的过程:

假如重复了:

rehash

再来看看哈希表总体图中左边橘黄色的“统筹”部分,其中有两个关键的属性:htrehashidxht是一个数组,有且只有俩元素ht[0]和ht[1];其中,ht[0]存放的是redis中使用的哈希表,而ht[1]和rehashidx和哈希表的rehash有关。rehash指的是重新计算键的哈希值和索引值,然后将键值对重排的过程。加载因子(load factor) = ht[0].used / ht[0].size

扩容和收缩标准

扩容:

  • 没有执行BGSAVE和BGREWRITEAOF指令的情况下,哈希表的加载因子大于等于1。
  • 正在执行BGSAVE和BGREWRITEAOF指令的情况下,哈希表的加载因子大于等于5。

收缩:

  • 加载因子小于0.1时,程序自动开始对哈希表进行收缩操作。

扩容和收缩的数量

扩容:

  • 第一个大于等于ht[0].used * 22^n(2的n次方幂)。

收缩:

  • 第一个大于等于ht[0].used2^n(2的n次方幂)。

(以下部分属于细节分析,可以跳过直接看扩容步骤) 对于收缩,我当时陷入了疑虑:收缩标准是加载因子小于0.1的时候,也就是说假如哈希表中有4个元素的话,哈希表的长度只要大于40,就会进行收缩,假如有一个长度大于40,但是存在的元素为4即(ht[0].used为4)的哈希表,进行收缩,那收缩后的值为多少?我想了一下:按照前文所讲的内容,应该是4。 但是,假如是4,存在和收缩后的长度相等,是不是又该扩容? 翻开源码看看,收缩具体函数:

int dictResize(dict *d)     //缩小字典d
{int minimal;//如果dict_can_resize被设置成0,表示不能进行rehash,或正在进行rehash,返回出错标志DICT_ERRif (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR;minimal = d->ht[0].used;            //获得已经有的节点数量作为最小限度minimalif (minimal < DICT_HT_INITIAL_SIZE)//但是minimal不能小于最低值DICT_HT_INITIAL_SIZE(4)minimal = DICT_HT_INITIAL_SIZE;return dictExpand(d, minimal);      //用minimal调整字典d的大小
} 
int dictExpand(dict *d, unsigned long size)     //根据size调整或创建字典d的哈希表
{dictht n; unsigned long realsize = _dictNextPower(size);  //获得一个最接近2^n的realsizeif (dictIsRehashing(d) || d->ht[0].used > size) //正在rehash或size不够大返回出错标志return DICT_ERR;if (realsize == d->ht[0].size) return DICT_ERR; //如果新的realsize和原本的size一样则返回出错标志/* Allocate the new hash table and initialize all pointers to NULL *///初始化新的哈希表的成员n.size = realsize;n.sizemask = realsize-1;n.table = zcalloc(realsize*sizeof(dictEntry*));n.used = 0;/* Is this the first initialization? If so it's not really a rehashing* we just set the first hash table so that it can accept keys. */if (d->ht[0].table == NULL) {   //如果ht[0]哈希表为空,则将新的哈希表n设置为ht[0]d->ht[0] = n;return DICT_OK;}d->ht[1] = n;           //如果ht[0]非空,则需要rehashd->rehashidx = 0;       //设置rehash标志位为0,开始渐进式rehash(incremental rehashing)return DICT_OK;
}
static unsigned long _dictNextPower(unsigned long size)
{unsigned long i = DICT_HT_INITIAL_SIZE; //DICT_HT_INITIAL_SIZE 为 4if (size >= LONG_MAX) return LONG_MAX + 1LU;while(1) {if (i >= size)return i;i *= 2;}
}

由代码我们可以看到,假如收缩后长度为4,不仅不会收缩,甚至还会报错。(

Redis学习总结(14)——图解redis五种数据结构底层实现(动图版)相关推荐

  1. 字符动图_图解redis五种数据结构底层实现(动图哦)

    redis有五种基本数据结构:字符串.hash.set.zset.list.但是你知道构成这五种结构的底层数据结构是怎样的吗?今天我们来花费五分钟的时间了解一下.(目前redis版本为3.0.6) 动 ...

  2. 图解redis五种数据结构底层实现

    redis有五种基本数据结构:字符串.hash.set.zset.list.但是你知道构成这五种结构的底层数据结构是怎样的吗?今天我们来花费五分钟的时间了解一下.(目前redis版本为3.0.6) 动 ...

  3. 图解 Redis 五种数据结构底层实现

    Redis 是一个基于内存中的数据结构存储系统,可以用作数据库.缓存和消息中间件.Redis 支持五种常见对象类型:字符串(String).哈希(Hash).列表(List).集合(Set)以及有序集 ...

  4. Redis学习---(14)Redis 事务

    Redis 事务 Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证: 批量操作在发送 EXEC 命令前被放入队列缓存. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其 ...

  5. Redis入门总结(一):redis配置文件,五种数据结构,线程模型和持久化方式

    (尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/90321396冷血之心的博客) 关注微信公众号(文强的技术小屋) ...

  6. 万字长文的Redis五种数据结构详解(理论+实战),建议收藏。

    本文脑图 前言 Redis是基于c语言编写的开源非关系型内存数据库,可以用作数据库.缓存.消息中间件,这么优秀的东西一定要一点一点的吃透它. 关于Redis的文章之前也写过三篇,阅读量和读者的反映都还 ...

  7. Redis五种数据结构详解

    Redis是基于c语言编写的开源非关系型内存数据库,可以用作数据库.缓存.消息中间件,这么优秀的东西一定要一点一点的吃透它. Redis的五种数据结构包括以下五种: String:字符串类型 List ...

  8. Redis五种数据结构

    对redis来说,所有的key(键)都是字符串,所谓的5种数据结构是指针对value而言 1.Redis五种数据结构如下: 数据结构类型 说明 使用场景 常用方法 其他链接 String字符串类型 1 ...

  9. 浅谈Redis五种数据结构的底层原理

    概念 Redis作为一个开源的用C编写的非关系型数据库,基于优秀的CRUD效率,常用于软件系统的缓存,其本身提供了以下五种数据格式: string:字符串 list:列表 hash:散列表 set:无 ...

最新文章

  1. LeetCode Single Number II(位操作)
  2. Android碎片化难题:手游兼容性测试应该适配哪些机型?
  3. 基于哈希算法的web账户口令存储方法
  4. fedora17的gnome3桌面美化
  5. 天津和塘沽两天一夜自由行(第一天)
  6. 爱立信携手沃达丰完成英国首个5G独立组网网络切片试验
  7. complete_code_Chapter1
  8. Oracle中的环境变量(ORACLE_HOME 和 ORACLE_SID)
  9. Linux学习笔记--终端命令
  10. Rethinking the smaller-norm-less-infromative assumption in channel pruning of convolution layers
  11. 微信抖音社区团购小程序源码开发方案怎么做
  12. 十二笔记(一):winfrom 引用 FastReport.dll 打印标签
  13. 数据库原理与应用实验十 数据库完整性实验
  14. 微信图片服务器逻辑,关于图片上传原图会被压缩的解决方案
  15. 【MATLAB】P图神器,初露锋芒:第一周作业
  16. 阿里算法实习生面试回忆
  17. unity 麻将 用于打出去牌后在桌面相应的位置生成发出去的牌
  18. GitHub 又一可视化低代码神器,诞生了!
  19. 易语言获取网络文件正常
  20. 基于FPGA实现的流水灯项目

热门文章

  1. LeetCode-35 搜索插入位置
  2. python编程30题_python编程30个常用技巧
  3. c语言编写简单的成绩管理系统,用c语言编写学生成绩管理系统
  4. python裁剪图片box并保存_python实现图像随机裁剪
  5. sqlserver日志文件在哪_用友SQL SERVER数据库置疑修复实例
  6. 小程序 cover-view 字体_【企商云】2021年,要知道的9个小程序开发流程清单
  7. C++之构造函数和类型转换探究
  8. C++之Big Three:拷贝构造、拷贝赋值、析构函数探究
  9. 阅读java文件_阅读与阅读写文件 - Java空格
  10. python语言type board_Micropython TPYBoard开发板控制无线加速度小车