第一篇文章,思来想去,写一写Redis吧,最近在深入研究它。

一丶Redis底层结构

1. redis 存储结构

  • redis的存储结构从外层往内层依次是redisDb、dict、dictht、dictEntry。
  • redis的Db默认情况下有16个,每个redisDb内部包含一个dict的数据结构。
  • redis的dict内部包含dictht的数组,数组个数为2,主要用于hash扩容使用。
  • dictht内部包含dictEntry的数组,可以理解就是hash的桶,然后如果冲突通过挂链法解决

redisServer内部包含着 redisDb *db的数组元素,只是用指针体现而已。

redisDb内部包含着dict *dict和dict *expires,用于存储数据和过期事件。

dict内部包含 dictht ht[2],是存储数据的对象,之所以有两个元素是为了扩容方便。

真正保存数据的核心数据结构, dictEntry **table可以理解为hash的桶,通过挂链法解决冲突。

存储数据的单个节点,包含key和value。保存我们存储在redis的数据。

2.redis 数据存储过程

数据存储过程以set为例作为说明,过程如下:

  • 从redisDb当中找到dict,每个db就一个dict而已。
  • 从dict当中选择具体的dictht对象。
  • 首先根据key计算hash桶的位置,也就是index。
  • 新建一个DictEntry对象用于保存key/value,将新增的entry挂到dictht的table对应的hash桶当中,每次保存到挂链的头部。
  • dictSetKey的宏保存key
  • dictSetVal的宏保存value

3.redis 过期事件存储过程

redis的过期事件存储在db->expires的对象当中,整个设置过期时间的过程如下:

  • 从db-dict获取原来存储数据,之所以去取数是为了保证key的存在性
  • 从db->expires获取旧的过期事件并重新计算过期时间dictReplaceRaw
  • 过期时间重新保存到DictEntry当中,也就是db->expires中的某个对象。

4.命令执行过程

整个redis的server端命令执行过程就如下面这个流程图:

  1. nio层读取数据
  2. 解析数据到命令行格式
  3. 查找命令对应的执行函数执行命令
  4. 同步数据到slave和aof

二丶Redis底层数据结构

1.string

  • 整数:存储字符串长度小于21且能够转化为整数的字符串。
  • emstr:存储字符串长度小于39的字符串
  • sds:剩余情况使用sds进行存储。

embstr和sds的区别在于内存的申请和回收

embstr的创建只需分配一次内存,而raw为两次(一次为sds分配对象,另一次为redisObject分配对象,embstr省去了第一次)。相对地,释放内存的次数也由两次变为一次。

embstr的redisObject和sds放在一起,更好地利用缓存带来的优势

缺点:redis并未提供任何修改embstr的方式,即embstr是只读的形式。对embstr的修改实际上是先转换为raw再进行修改。

用SDS保存字符串 “Redis”具体图示如下:

2.List

redis list数据结构底层采用压缩列表ziplist或linkedlist两种数据结构进行存储,首先以ziplist进行存储,在不满足ziplist的存储要求后转换为linkedlist列表。

当列表对象同时满足以下两个条件时,列表对象使用ziplist进行存储,否则用linkedlist存储。

  • 列表对象保存的所有字符串元素的长度小于64字节
  • 列表对象保存的元素数量小于512个。

redis list元素添加过程:

list的数据添加根据传入的变量个数一个个顺序添加,整个顺序如下:

  • 创建list对象并添加到db的数据结构当中
  • 针对每个待插入的元素添加到list当中
  • list的每个元素的插入过程中,我们会对是否需要进行转码作两个判断:
  • 对每个插入元素的长度进行判断是否进行ziplist->linkedlist的转码。
  • 对list总长度是否超过ziplist最大长度的判断。

3.hashmap

redis的哈希对象的底层存储可以使用ziplist(压缩列表)和hashtable。当hash对象可以同时满足一下两个条件时,哈希对象使用ziplist编码。

  • 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节
  • 哈希对象保存的键值对数量小于512个

4.set

redis的集合对象set的底层存储结构特别神奇,我估计一般人想象不到,底层使用了intset和hashtable两种数据结构存储的,intset我们可以理解为数组,hashtable就是普通的哈希表(key为set的值,value为null)。是不是觉得用hashtable存储set是一件很神奇的事情。

set的底层存储intset和hashtable是存在编码转换的,使用intset存储必须满足下面两个条件,否则使用hashtable,条件如下:

  • 结合对象保存的所有元素都是整数值
  • 集合对象保存的元素数量不超过512个

5.zset

zset底层的存储结构包括ziplist或skiplist,在同时满足以下两个条件的时候使用ziplist,其他时候使用skiplist,两个条件如下:

  • 有序集合保存的元素数量小于128个
  • 有序集合保存的所有元素的长度小于64字节

当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。

当skiplist作为zset的底层存储结构的时候,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。

6.数据结构

ziplist:

压缩列表,压缩列表(ziplist)是Redis为了节省内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。

压缩列表的原理:压缩列表并不是对数据利用某种算法进行压缩,而是将数据按照一定规则编码在一块连续的内存区域,目的是节省内存。

ziplist的数据结构主要包括两层,ziplist和zipEntry。

  • ziplist包括zip header、zip entry、zip end三个模块。
  • zip entry由prevlen、encoding&length、value三部分组成。
  • prevlen主要是指前面zipEntry的长度,coding&length是指编码字段长度和实际- 存储value的长度,value是指真正的内容。
  • 每个key/value存储结果中key用一个zipEntry存储,value用一个zipEntry存储。

 inset:

intset内部其实是一个数组(int8_t coentents[]数组),而且存储数据的时候是有序的,因为在查找数据的时候是通过二分查找来实现的。整数集合(intset)是Redis用于保存整数值的集合抽象数据类型,它可以保存类型为int16_t、int32_t 或者int64_t 的整数值,并且保证集合中不会出现重复元素。

整数集合的每个元素都是 contents 数组的一个数据项,它们

升级

当我们新增的元素类型比原集合元素类型的长度要大时,需要对整数集合进行升级,才能将新元素放入整数集合中。具体步骤:

  1. 根据新元素类型,扩展整数集合底层数组的大小,并为新元素分配空间。
  2. 将底层数组现有的所有元素都转成与新元素相同类型的元素,并将转换后的元素放到正确的位置,放置过程中,维持整个元素顺序都是有序的。
  3. 将新元素添加到整数集合中(保证有序)。

升级能极大地节省内存。

降级

整数集合不支持降级操作,一旦对数组进行了升级,编码就会一直保持升级后的状态。

按照从小到大的顺序排列,并且不包含任何重复项。

length 属性记录了 contents 数组的大小。

需要注意的是虽然 contents 数组声明为 int8_t 类型,但是实际上contents 数组并不保存任何 int8_t 类型的值,其真正类型有 encoding 来决定。

skiplist:

跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的。具有如下性质:

  1. 由很多层结构组成;
  2. 每一层都是一个有序的链表,排列顺序为由高层到底层,都至少包含两个链表节点,分别是前面的head节点和后面的nil节点;
  3. 最底层的链表包含了所有的元素;
  4. 如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集);
  5. 链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点;

Redis底层结构全了解的更多相关文章

  1. Redis底层结构概述

    可以使用 object encoding <key> 查看使用的具体数据结构 原图链接

  2. Redis短结构

    本章将介绍3种非常有价值的降低Redis内存占用的方法.降低Redis的内存占用有助于减少创建快照和加载快照所需的时间.提升载入AOF文件和重写AOF文件时的效率.缩短从服务器进行同步所需的时间,并且 ...

  3. Redis的结构和运作机制

    目录 1.数据库的结构 1.1 字典的底层实现 2.过期键的检查和清除 2.1 定时删除 2.2 惰性删除 2.3 定期删除 2.4 对RDB.AOF和复制的影响 3.持久化机制 3.1 RDB方式 ...

  4. Redis短结构与分片

    本文将介绍两种降低Redis内存占用的方法——使用短结构存储数据和对数据进行分片. 降低Redis内存占用有助于减少创建快照和加载快照所需的时间.提升载入AOF文件和重写AOF文件时的效率.缩短从服务 ...

  5. redis底层设计(三)——redis数据类型

    今天我们来看一下redis的数据类型.既然redis的键值对可以保存不同类型的值,那么很自然就需要对键值对的类型进行检查以及多态处理.下面我们将对redis所使用的对象系统进行了解,并分别观察字符串. ...

  6. redis底层设计(一)——内部数据结构

    redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...

  7. 对于redis底层框架的理解(一)

    近期学习了redis底层框架,好多东西之前都没听说过,算是大开眼界了. 先梳理下redis正常的通讯流程吧 首先服务器启动都有主函数main,这个main函数就在redis.c里 首先是initser ...

  8. 恋恋风辰 对于redis底层框架的理解(一)

    近期学习了redis底层框架,好多东西之前都没听说过,算是大开眼界了. 先梳理下redis正常的通讯流程吧 首先服务器启动都有主函数main,这个main函数就在redis.c里 首先是initser ...

  9. Redis 底层数据结构介绍

    Redis 底层数据结构 版本:2.9 支持的数据类型: 字符串 散列 列表 集合 有序集合 字符串 Redis 利用原生的 c 字符串进行了一次封装.封装的字符串叫做简单动态字符串:SDS(simp ...

随机推荐

  1. 大清朝早亡了,还没有入门 Spring Boot?

    由于读者的数量越来越多,难免会被问到一些我自己都觉得不好意思的问题,比如说前几天小王就问我:"二哥,快教教我,怎么通过 Spring Boot 创建一个 Hello World 项目啊?&q ...

  2. search(16)- elastic4s-内嵌文件:nested and join

    从SQL领域来的用户,对于ES的文件关系维护方式会感到很不习惯.毕竟,ES是分布式数据库只能高效处理独个扁平类型文件,无法支持关系式数据库那样的文件拼接.但是,任何数据库应用都无法避免树型文件关系,因 ...

  3. Python实现批量处理文件的缩进和转码问题

    最近把很久前的C代码传到Github上的时候,发现全部上百个源文件的代码缩进都变成了8格,而且里面的中文都出现了乱码,所以决定写个程序来批量处理所有文件的格式.这段关于转码的代码可以适用于很多场合,比 ...

  4. CF832C

    题目链接:http://codeforces.com/contest/832/problem/C 题目大意: n个人,面向左或者右站在同一条轴上,每个人在轴上的坐标为x,速度为v.请你在某个位置放置一 ...

  5. 8.8SQL Server数据类型介绍1

    image类型:存储二进制字节数组. (相当于C#中的byte[]字节类型) sql server常用的数据类型 1.image类型,用来存储byte[](字节). 2.字符串类型 char ncha ...

  6. CPU上下文切换以及相关指标的理解

      前言 上下文切换这个词一直不理解,看了无数遍就忘了无数遍,知道看到<操作系统导论>这本书,终于有了略微的理解.这也证明了我的方向是没错的,一直认为做运维还是得理解底层的知识,不理解很多 ...

  7. 解决2003 - 2003 - Can't connect to MySQL server on '127.0.0.1'(61 "Connection refused")

    1)右击数据库选择编辑连接2) 3)重新输入密码即可

  8. mybatis的多表联查

    多对一连表查询简单记录

  9. Unity实现byte[]合成图像

    bool CreateCovers(byte[] imageData) { Texture2D imageTexture = new Texture2D(273, 126); imageTexture ...

  10. [SD喜爱语言PK大赛]001.PHP vs Node.js

    引言:近日,两大编程飓风之战已经愈演愈烈.在程序员社区,一些争端因PHP与Node.js而起. 观点:其实就本人及团队而言,Language just a language!不存在高低之分,而侧重的原 ...