Redis 五大类型源码及底层实现

news2024/11/26 11:54:29

面试题:

谈谈Redis数据类型的底层数据结构:

  • SDS动态字符串
  • 双向链表
  • 玉缩列表ziplist
  • 哈希表hashtable
  • 跳表kiplist
  • 整数集合intset
  • 快速列表quicklist
  • 紧凑列表listpack

Redis源代码的核心部分

官网:GitHub - redis/redis: Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps.

源码位置:\redis-7.0.5\src

Redis基本数据结构

官网说明:

主要包括这些源码文件:Redis对象 object.c、字符串 t_string.c、列表 t_list.c、字典 t_hash.c、集合及有序集合 t_set.c 和 t_zset.c、数据流 t_stream.c(Streams的底层实现结构 listpack.c 和 rax.c)。

还包括:简单动态字符串 sds.c、整数集合 intset.c、压缩列表 ziplist.c、快速链表 quicklist.c、listpack字典 dict.c

Redis数据库的实现

  1. 数据库的底层实现 db.c
  2. 持久化 rdb.c 和 aof.c

Redis服务端和客户端实现

  1. 事件驱动 ae.c 和 ae_epoll.c
  2. 网络连接 anet.c 和 networking.c
  3. 服务满程序 server.c
  4. 客户端程序
  5. edis-cli.c

其他实现

  1. 主从复制replication.c
  2. 哨兵  sentinel.c
  3. 集群 cluster.c
  4. 其他数结构,如 hyperloglog.c、geo.c 等
  5. 其他功能,如 pub/sub、Lua 脚本

Redis字典数据库中 KV 键值对到底是什么

如何实现键值对(key-value)数据库的

redis是key-value存储系统,key一般都是String类型的字符串对象,value类型则为redis对象(redisObject)

注:value可以是字符串对象,也可以是集合数据类型的对象,比如List对象、Hash对象、Set对象和Zset对象。

十大类型说明

传统 5 大类型:String、List、Hash、Set、ZSet

新介绍的 5 大类型:

bitmap:实质String
hyperLogLog:实质String
GEO:实质Zset
Stream:实质Stream
BITFIELD:看具体key

上帝视角

Redis定义了redisObjec结构体来表示string、hash、list、set、zset等数据类型

Redis中每个对象都是一个redisObject结构。

字典、KV是什么(重点

每个键值对都会有一个dictEntry


源码位置:(dict.h)

重点:从dictEntry到RedisObject

这些键值对是如何保存进Redis并进行读取操作,O(1)复杂度

redisObject+Redis数据类型+Redis所有编码方式(底层实现)三者之间的关系

5大结构底层语言源码分析

C语言struct结构体语法简介

Redis数据类型与数据结构总纲图

源码分析总体数据结构大纲:

1.SDS动态字符串
2.双向链表
3.压缩列表ziplist
4.哈希表hashtable
5.跳表skiplist
6.整数集合intset
7.快速列表quicklist
8.紧凑列表listpack

redis6之前,老版本

Redis7版本

源码分析总体数据结构大纲

redisObject操作底层定义来自那里?

举例

从set hello world说起,每个键值对都会有一个dictEntry。

set hello word为例,因为Redis是KV键值对的数据库,每个键值对都会有一个dictEntry(源码位置:dict.h),里面指向了key和value的指针,next 指向下一个 dictEntry。

key 是字符串,但是 Redis 没有直接使用 C 的字符数组,而是存储在redis自定义的 SDS中。

value 既不是直接作为字符串存储,也不是直接存储在 SDS 中,而是存储在redisObject 中

实际上五种常用的数据类型的任何一种,都是通过 redisObject 来存储的。

备注:

查看key类型:type key

查看key编码:object encoding hello

redisObjec结构的作用

        为了便于操作,Redis采用redisObjec结构来统一五种不同的数据类型,这样所有的数据类型就都可以以相同的形式在函数间传递而不用使用特定的类型结构。同时,为了识别不同的数据类型,redisObjec中定义了type和encoding字段对不同的数据类型加以区别。简单地说,redisObjec就是string、hash、list、set、zset的父类,可以在函数间传递时隐藏具体的类型信息,所以作者抽象了redisObjec结构来到达同样的目的。

RedisObject各字段的含义

解释:

1、4位的type表示具体的数据类型

2、4位的encoding表示该类型的物理编码方式见下表,同一种数据类型可能有不同的编码方式。(比如String就提供了3种:int embstr raw)

3、lru字段表示当内存超限时采用LRU算法清除内存中的对象。

4、refcount表示对象的引用计数。

5、ptr指针指向真正的底层数据结构的指针。

举例:

前置知识

各个类型的数据结构的编码映射和定义

Debug Object key 使用

开启debug模式:

配置文件config修改 enable-debug-command local

开启前 

开启后

解释:

1、Value at: 内存地址

2、refcount: 引用次数

3、encoding: 物理编码类型

4、serializedlength: 序列化后的长度(注意这里的长度是序列化后的长度,保存为rdb文件时使用了该算法,不是真正存贮在内存的大小),会对字串做一些可能的压缩以便底层优化

5、lru:记录最近使用时间戳

6、lru_seconds_idle:空闲时间

String数据结构介绍

3大物理编码方式

RedisObject内部对应3大物理编码:int、embstr、raw

1、int 编码

保存long型(长整型)的64位(8个字节)有符号整数。最大值:9223372036854775807,其中数字最多19位。

补充:只有整数才会使用int,如果是浮点数,Redis内部其实先将浮点数转化为字符串值,然后再保存。

2、embstr 编码

代表embstr格式的SDS(Simple Dynamic String 简单动态字符串),保存长度小于44字节的字符串。

embstr 顾名思义即:embedded string,表示嵌入式的String。

3、raw 编码

保存长度大于44字节的字符串。

编码案例

C语言中的字符串形式: 

假如现在展现一个字符串:Redis

Redis没有直接复用C语言的字符串,而是新建了属于自己的结构-----SDS

在Redis数据库里,包含字符串值的键值对都是由SDS实现的(Redis中所有的键都是由字符串对象实现的即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现)。

源码分析

官网:GitHub - antirez/sds: Simple Dynamic Strings library for C

1、sds.h源码分析

说明

Redis中字符串的实现,SDS有多种结构(sds.h):
sdshdr5、(2^5=32byte)
sdshdr8、(2 ^ 8=256byte)
sdshdr16、(2 ^ 16=65536byte=64KB)
sdshdr32、 (2 ^ 32byte=4GB)
sdshdr64,2的64次方byte=17179869184G用于存储不同的长度的字符串。
 
len 表示 SDS 的长度,使我们在获取字符串长度的时候可以在 O(1)情况下拿到,而不是像 C 那样需要遍历一遍字符串。
 
alloc 可以用来计算 free 就是字符串已经分配的未使用的空间,有了这个值就可以引入预分配空间的算法了,而不用去考虑内存分配的问题。
 
buf 表示字符串数组,真存数据的。

2、Redis为什么重新设计一个SDS数据结构?

C语言没有Java里面的String类型,只能是靠自己的char[]来实现,字符串在 C 语言中的存储方式,想要获取 「Redis」的长度,需要从头开始遍历,直到遇到 '\0' 为止。所以,Redis 没有直接使用 C 语言传统的字符串标识,而是自己构建了一种名为简单动态字符串 SDS(simple dynamic string)的抽象类型,并将 SDS 作为 Redis 的默认字符串。

3、set k1 v1命令底层发生了什么?调用关系是怎么样的

4、INT编码格式

命令示例: set k3 123

当字符串键值的内容可以用一个64位有符号整形来表示时,Redis会将键值转化为long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。内部的内存结构表示如下:

Redis 启动时会预先建立 10000 个分别存储 0~9999 的 redisObject 变量作为共享对象,这就意味着如果 set字符串的键值在 0~10000 之间的话,则可以 直接指向共享对象 而不需要再建立新对象,此时键值不占空间!

set k1 123

set k2 123

源码内容

redis源代码:server.h(定义一个共享变量)

redis6源代码:object.c

redis7源代码:object.c

5、EMBSTR编码格式

命令示例:set k3 abc

redis源代码:object.c

        对于长度小于 44的字符串,Redis 对键值采用OBJ_ENCODING_EMBSTR 方式,EMBSTR 顾名思义即:embedded string,表示嵌入式的String。从内存结构上来讲 即字符串 sds结构体与其对应的 redisObject 对象分配在同一块连续的内存空间,字符串sds嵌入在redisObject对象之中一样。

进一步createEmbeddedStringObject方法

 

redis源代码:object.c

高明之处:ptr指针指向下一个地址。

6、RAW编码格式

命令示例:set k3 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz

        当字符串的键值为长度大于44的超长字符串时,Redis 则会将键值的内部编码方式改为OBJ_ENCODING_RAW格式,这与OBJ_ENCODING_EMBSTR编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续了。

个别情况:明明没有超过阈值,为什么变成raw了

结果:判断不出来,就取最大Raw

逻辑图

案例结论

1、只有整数才会使用 int,如果是浮点数, Redis 内部其实先将浮点数转化为字符串值,然后再保存。

2、embstr 与 raw 类型底层的数据结构其实都是 SDS (简单动态字符串,Redis 内部定义 sdshdr 一种结构)。

这两者的区别见下图:

1、int:Long类型整数时,RedisObject中的ptr指针直接赋值为整数数据,不再额外的指针再指向整数了,节省了指针的空间开销。

2、embstr:当保存的是字符串数据且字符串小于等于44字节时,embstr类型将会调用内存分配函数,只分配一块连续的内存空间,空间中依次包含 redisObject 与 sdshdr 两个数据结构,让元数据、指针和SDS是一块连续的内存区域,这样就可以避免内存碎片。

3、raw:当字符串大于44字节时,SDS的数据量变多变大了,SDS和RedisObject布局分家各自过,会给SDS分配多的空间并用指针指向SDS结构,raw 类型将会调用两次内存分配函数,分配两块内存空间,一块用于包含 redisObject结构,而另一块用于包含 sdshdr 结构。

结果:Rdis内部会根据用户给的不同键值而使用不同的编码格式,自适应地选择较优化的内部编码格式,而这一切对用户完全透明!

Hash数据结构介绍

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1009184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jenkins自动化脚本集成时钉钉消息未发送

在进行jenkins自动化脚本集成时,需要配置钉钉发送消息。钉钉的配置正确,测试钉钉消息发送成功,但是当构建项目时,却没有收到钉钉消息,报错如下: [钉钉插件]发送消息时报错: java.lang.NullPointerExceptio…

项目经理晋升为企业高管,需要杀死自己三次

大家好,我是老原。 “猴子屁股理论”,大家应该都知道吧。 就拿职场来说,它就像是一棵树,从树底下开始爬,一层一层的基层员工-基层干部-中层干部-高层-老板。 你会发现,无论你在哪一层,往上看都…

PyTorch实战-实现神经网络图像分类基础Tensor最全操作详解(二)

前言 PyTorch可以说是三大主流框架中最适合初学者学习的了,相较于其他主流框架,PyTorch的简单易用性使其成为初学者们的首选。这样我想要强调的一点是,框架可以类比为编程语言,仅为我们实现项目效果的工具,也就是我们…

开始使用Filebeat

认识Beats Beats是用于单用途数据托运人的平台。它们以轻量级代理的形式安装,并将来自成百上千台机器的数据发送到Logstash或Elasticsearch。 (画外音:通俗地理解,就是采集数据,并上报到Logstash或Elasticsearch&…

用matlab在hfss中建模

hfss可以导入vbs语言建模 怎么生成建模的vbs文档? 1.在hfss中建模建一遍 导出建模的vbs,然后笔记本打开vbs,需要改的话直接改。 参考 https://blog.csdn.net/m0_56117494/article/details/128007860 一文 这个方法朴实无华 但是需要写vbs语言…

英语单词(6)

1.person 人 2.start 开始 3.menu 菜单 4.login 登录 5.main 主要的 6.document 文档 7.display 显示 8.method 方法,条理 9.version 版本 10parameter 参数

Leecode1160: 拼写单词

直接使用一个哈希表存整体的结果,一个临时的哈希表每次算一遍,但是1是要设置标志位来判断最后是否正确并加上长度,2是千万要记得每次新建一个空间来存哈希表绝对不能不空间就等于,会出事!!

【小吉送书—第三期】Linux私教课:技术内核与企业运维篇

文章目录 🍔查找⭐find命令🎈按文件名🎈按拥有者🎈查找Linux系统下大于200M的文件 ⭐locate命令🎈使用方法 ⭐which命令(查找指令的,而不是文件)🎈使用方法 ⭐grep命令和…

Appium混合页面点击方法tap的使用

原生应用开发,是在Android、IOS等移动平台上利用官方提供的开发语言、开发类库、开发工具进行App开发;HTML5(h5)应用开发,是利用Web技术进行的App开发。目前,市面上很多app都是原生和h5混合开发&#xff0c…

【推荐】SpringMVC与JSON数据返回及异常处理机制的使用

🎬 艳艳耶✌️:个人主页 🔥 个人专栏 :《【推荐】Spring与Mybatis集成整合》 ⛺️ 生活的理想,为了不断更新自己 ! 1.JSON 在SpringMVC中,JSON数据返回通常是通过使用ResponseBody注解将Java对象转换为JSO…

2023年有哪些值得推荐的深度学习书?

深度学习指的是用一种特定的方法来解决一些机器学习的问题。 这种方法的中心思想是:基于一系列的离散的层(layer) 构建机器学习算法。如果将这些层 垂直堆叠,就说这个结果是有深度 (depth)的,或…

淘宝新品店铺运营必做的任务!

首先我们需要知道,新品上线前需要进行私域预热,以便达到上新后的销量效果,那上线后的运营又该怎么做呢? “ 完成新品孵化任务 进入【千牛后台】-【商品】-【新品运营】 这里可以看到淘宝针对新品扶持新开的板块,可以…

遥测终端机RTU助力城市内涝监测系统

一、背景概述 2023年第5号台风“杜苏芮”,周末登陆福建晋江,一波未平一波又起,卡努台风也进入了48小时警戒线,台风侵袭给城市基础设施和居民生活带来了严重的影响。后面第11号台风“海葵”号随之带来了更多城市内涝问题&#xff0…

Mobile Vision Transformer-based Visual Object Tracking

论文作者:Goutam Yelluru Gopal,Maria A. Amer 作者单位:Concordia University 论文链接:https://arxiv.org/pdf/2309.05829v1.pdf 项目链接:https://github.com/goutamyg/MVT 内容简介: 1)方向&#…

添加Typora主题皮肤

到官网下载喜欢的主题皮肤,比如【vue风格】 https://theme.typora.io 下载压缩包 打开 typora 主题皮肤文件夹 将解压后文件夹中的 vue文件夹 和 vue.css 复制到 主题皮肤文件夹中 重启 typora ,主题菜单中选择 新装的 vue 皮肤即可

华为云云耀云服务器L实例评测|基于云耀云服务器部署Samba服务

本实验将使用华为云云耀云服务器L实例,使用CentOS 7.9系统,搭建部署Samba服务器,并在本地Windows端进行访问。 文章目录 1、samba介绍2、环境准备3、安装samba软件包4、修改smb.conf配置文件5、添加访问samba的用户6、Windows下访问Samba服务…

三、数学建模之非线性规划

1、定义 2、例题matlan代码求解 一、定义 1.非线性规划(Nonlinear Programming,简称NLP)是一种数学优化问题的方法,它处理的目标函数或约束条件包含非线性项。与线性规划不同,非线性规划涉及到在非线性约束下寻找最优…

【Y 新闻】YMatrix携手三一集团,荣获“2023爱分析·数据库最佳实践案例”

2023 年 8 月 16 日,由爱分析主办的第五届数据智能高峰论坛在北京 JW 万豪酒店成功举办。本次论坛以“激活数据资产,释放数据价值”为主题,聚焦企业在数据能力和数据应用建设过程中所面临的系列问题。会上,由 YMatrix 与三一集团携…

iPhone15发布,苹果和台积电的牛皮都破了,3纳米没那么神奇

在发布会之前,A17处理器和3纳米工艺被吹得神乎其神,随着iPhone15的发布,两者也终于在人们面前显示出真面目,事实就是先进工艺并没那么厉害,多花的钱并不值。 苹果在发布会上表示A17Pro处理器的CPU性能最高提升10%&…

背包问题---怎么选取物品,可以使得背包装的物品价值最大?

原文: https://zhuanlan.zhihu.com/p/567560364 1)0-1背包问题的描述 现在有四种物品,每种物品只有1件,它们的重量与价值如下表。 现在有一个背包,总容量为8。问怎么选取物品,可以使得背包装的物品价值…