Redis 全景图(1)--- 关于 Redis 的6大模块

这是我第一次尝试以长文的形式写一篇 Redis 的总结文章。这篇文章我想写很久了,只是一直碍于我对 Redis 的掌握没有那么的好,因此迟迟未动笔。这几天,我一直在看各种不同类型的 Redis 文章,通过阅读这些文章,引发了我对于 Redis 这个大知识点的很多思考。我看过的一篇又一篇的文章都帮助着将我脑子里我学过的 Redis 的零散知识点整合在一起,从而构建一个 Redis 全局系统观,帮助着我用一个全局的方式看待 Redis 这个存储系统。接下来,我计划用文字的方式,将我脑子里的 Redis 蓝图一一描绘出来。

Redis?什么是 Redis?Redis 就是一个键值对数据库。所以,当别人跟你说 Redis 的时候,你的脑子里应该立马想到键值对数据库。我一开始以为这就是 Redis,其实这并不是,这仅仅是 Redis 的其中一个模块而已。对于一个完整的 Redis,应该是由6大模块组成的:访问模块、索引模块、操作模块、存储模块、高可用集群模块、高可扩展集群模块。

访问模块

访问模块就是我们平时一定会接触的 Redis 的网络IO线程模型,如图:

Redis 是一个典型的 client-server 模型。首先,客户端先找 server-socket 建立连接,产生一个事件。IO多路复用器看到这么一个事件就把事件压入队列。文件事件分派器看到队列里有事件就把事件拿出来交给对应的事件处理器进行处理。处理过程是事件处理器会建立一个与客户端 socket 对应的新 socket。只要客户端 socket 与这个新 socket 通信,比如说发起了一个请求,新 socket 就会产生一个事件,然后IO多路复用器就会看到这个事件......重复上面的步骤。

这就是 Redis 的访问模块。访问模块也就是我们说的网络IO单线程模型。我的理解就是如果我们想访问 Redis 里面的键值对数据库,底层第一步要做的就是先进入这个键值对数据库,进入的方式就是我上面说的网络IO单线程模型。

索引模块

OK!回到刚才,我刚刚不是说了通过访问模块,我们已经访问到了键值对数据库了吗?那你有没有想过,这个键值对数据库是长什么样子的,又或者说这些键值对在 Redis 中是怎么存放的,那个画面你想过吗?其实是用一张全局哈希表来存放所有键值对的。这个哈希表由多个哈希桶组成,每个哈希桶存放一个或多个键值对。key 很好理解,因为 key 存放的只是 String 类型,但是 value 就不好理解了,value 支持很多种数据类型(String、列表、哈希、set、zset)。这些数据类型中,除了 String 类型之外,其他的几种类型都是数据集合。不过我当时在学习的时候就想象不出这个画面,我就想,一个 value 能存这么多数据?在我的理解里,我只能理解 value 是 String 类型的这种情况(value 是 String 类型的话,value 是存一个数据的,这很符合我的印象)。后来,我看到了一篇文章,然后我恍然大悟,原来 key-value 键值对存放的并不是实际的值,而是指针,这些指针指向数据集合!就像这样:

如果键值对越来越多,越来越多的话,我们就采用 rehash,即哈希扩容。这里的哈希扩容是渐进式的,没错,就是你学过的那个渐进式哈希扩容,每次对哈希表进行一次插入或者删除操作,就转移一个桶的数据到新表中,就像这样:

操作模块

OK!通过上面的文字和图片,我们应该大致知道 Redis 这个键值对数据库里面大概长什么样了,接下来我们来看看操作模块。操作模块其实就是对键值对的一些操作,除了一些最基础的 put、get、delete 之外,根据 value 中数据类型的不同,会有不同的操作方法。比如说,假如这个键值对的 value 的数据类型是列表 List,那么针对这种数据类型就提供 push 进队和 pop 出队这些对应的操作,就这么简单。

存储模块

这是 Redis 中最核心的模块了,因为这里知识点最多,但是又不是最难,我花了好多时间去理解这个知识点,理解了之后,感觉有种高山看海,海浪真美的感觉。

存储模块,研究的就是 value 中的5种数据类型和底层的6种数据结构,就像这个图:

String ——(动态字符串)

String 这种数据类型真的是万金油,名字虽然叫 String,但是它还可以存文本,数据.....感觉啥都能存。String 类型的底层数据结构是动态字符串,动态字符串提供了丰富的 String 操作命令:增减、排序、查找、计数.....比如我之前实习的公司,它就用 String 来做计数器,用来记录用户的刷新次数,防止一个用户一直刷新。

List ——(双向链表、压缩链表)

List这种数据类型的底层是双向链表的话,我们其实可以用 Redis 来做一个轻量的消息队列,具体怎么实现,我之前好像写过一篇文章:能否把 Redis 当做消息队列来用呢?-CSDN博客

而如果 List 的底层用压缩列表来实现的话,就体现出 Redis 很快很省。因为压缩列表,压缩嘛,肯定省,而且数据被压缩成连续的,所以查找起来就很快。

Hash ——(压缩列表、哈希表)

Hash 这种数据类型的底层实现可以是压缩列表或者是哈希表。如果底层实现是哈希表的话,那么 Redis 就可以用于缓存,比如说缓存用户的基本信息。怎么缓存用户的基本信息?就是 key 是用户ID,value 是用户的基本信息。

Set ——(哈希表、整数数组)

Set 这种数据类型的特点就是无序且不重复。之所有有这种特点,就是因为它底层的数据结构。哈希表是散列的是吧,散列那肯定就无序啊,而哈希表我们都学过不允许存重复的元素,所以数据就不重复。即哈希表是无序不重复的,因此Set也是无序不重复的。如果你用 Redis 来做消息队列的话,那么这个 Set 可以帮助保持消息队列的幂等性(即消息不被重复消费)。假如你理解不了这个例子,那换一个更加简单的,你肯定可以理解的例子。有一个数组a[5]=[2,4,2,4,7,6],你用一下Set,直接变成了[2,4,7,6],这你能理解了吧!

ZSet —— (压缩列表、跳跃表)

ZSet 和 Set 很像,只不过比起 Set,ZSet 是有序的,就这点不同,其他的感觉大差不差。比如说a[5]=[2,4,2,4,7,6],你用一下 ZSet,直接变成了[2,4,6,7]。所以Redis可以用于排行榜。

其实 Zset 本身并没有什么好讲的,但是 ZSet 底层用跳跃表这种数据结构来实现,跳跃表就可以好好讲讲了。假如我们用跳跃表这种数据结构来支持 ZSet 这种数据类型,那么在对 ZSet 这个有序集合的插入删除查找都是非常快的。跳跃表的原理我口头说不清,我觉得还是展示图片比较实在。我这里不谈跳跃表的插入删除操作,就谈跳跃表的查找操作。

说实话,其实我也不是很理解,暂时有点乱。不过关键的一点就是:通过上一层的元素来确定目标元素所在的区间。

我感觉跳跃表的查找就好像搭地铁一样,快线+慢线互相搭配,从而最快达到目的地。

高可用集群模块

高可用集群模块其实就是主从复制+哨兵机制,还有 AOF 和 RDB 技术。事实上感觉面试的 AOF和 RDB 技术这两个问的多一点,而主从复制+哨兵机制问的并不算多,也有可能是主从复制+哨兵机制相对而言比较复杂吧。关于 Redis 实现高可用的思想和 kafka 消息队列很像,特别是主从复制+哨兵机制那一块,感觉一模一样哈哈哈。

高可扩展集群模块

这个模块也没什么好讲的,Redis 就是通过数据分片来实现高扩展的。这一块感觉面试也问的不多,所以我也仅仅是做了简单的了解,并没有深挖太多。

总结

以上就是我脑图中的 Redis 的6大模块。假如你想要对键值对进行操作,首先你需要通过访问模块(网络IO单线程模型),然后你才可以进入到 Redis 的内部。在 Redis 内部,键值对是怎么存放的呢?其实是通过全局哈希表来存放所有键值对的,我也配了图,这就是索引模块。知道了 Redis 里面长什么样了,就到了真正对键值对进行操作了,操作模块其实就是一些简单的操作( put、get、delete ),加上 value 中不同数据类型提供的一些不同的操作。最后是存储模块,存储模块研究的问题是 value 中的值是用什么结构进行存储的,我们研究了5种数据类型以及这5种数据类型背后的6种底层数据结构,我也配了图,顺便说了一下这5种数据类型的一些使用场景。

其实这篇文章还没写完,但是 CSDN 的文章评分机制是,如果写太长的话,文章评分会降低,然后影响推流,所以我只好拆开来写了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nestjs 全栈进阶--控制器和参数获取

视频教程 06_nest控制器和参数获取1_哔哩哔哩_bilibili nest new argument -p pnpm nest g resource person pnpm start:dev 测试下:http://localhost:3000/person/1 在浏览器中看到图中的内容就是成功了 1. 路由 在Nest.js中,路由是由Controller装…

CTF比赛中JWT漏洞的利用

前言 在最近的ctf比赛中,经常可以碰到一些jwt相关的题目,然后感觉思路挺有意思,拿出来分享一下,后边也总结一下ctf比较常见的集jwt相关题目解题思路 算法混淆漏洞 腾龙杯 web[这又是一个登录页面] 使用zkaq/zkaq登录之后&#…

在编程中使用中文到底该不该??

看到知乎上有个热门问题,为什么很多人反对中文在编程中的使用? 这个问题有几百万的浏览热度,其中排名第一的回答非常简洁,我深以为然: 在国内做开发,用中文写注释、写文档,是非常好的习惯&…

【C+ +初阶】前言篇章---C+ +的广袤

目录 1.C语言到C的过渡 2.C的发展历程 2.1C语言的诞生 2.2 c的历史版本 3.c 的地位 4. c的应用场景 4.1. 操作系统以及大型系统软件开发 所有操作系统几乎都是C/C写的 4.2. 服务器端开发 后台开发: 4.3. 游戏开发 4.4. 嵌入式 4.5. 数字图像处理 4.6. 人工智能 4.7.…

pygame--坦克大战(二)

加载敌方坦克 敌方坦克的方向是随机的,使用随机数生成。 初始化敌方坦克。 class EnemyTank(Tank):def __init__(self,left,top,speed):self.images {U: pygame.image.load(img/enemy1U.gif),D: pygame.image.load(img/enemy1D.gif),L: pygame.image.load(img/e…

IP地址获取不到的原因是什么?

在数字化时代的今天,互联网已成为我们日常生活和工作中不可或缺的一部分。而IP地址,作为互联网通信的基础,其重要性不言而喻。然而,有时我们可能会遇到IP地址获取不到的问题,这会给我们的网络使用带来诸多不便。那么&a…

基于单片机的光伏电量检测系统的设计

**单片机设计介绍,基于单片机的光伏电量检测系统的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的光伏电量检测系统的设计概要主要围绕实现光伏电量的实时监测与精准测量展开。以下是该设计的主要内…

flutter获取手机中的系统路径信息

https://www.bilibili.com/video/BV1wE421g7sw获取系统中的路径 获取系统中的路径,并在这个路径中创建一个文本文件【str.txt】 然后进行写入【str.txt】 再读取这个文件【str.txt】 手机没有开通root权限无法看到写入到【应用程序文档目录】路径中的文件 用来…

大创项目推荐 深度学习 python opencv 火焰检测识别 火灾检测

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数:3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…

Node.js介绍

Node.js 是一个开源和跨平台的 JavaScript 运行时环境。它是几乎任何类型的项目的流行工具!

剑指Offer题目笔记25(使用回溯法解决其他类型问题)

面试题85: 问题: ​ 输入一个正整数n,输出所有包含n个左括号和n个右括号的组合,要求每个组合的左括号和右括号匹配。 解决方案: ​ 使用回溯法。因为要生成n个左括号和n个右括号,故需要走2n步&#xff0…

LabVIEW专栏三、探针和断点

探针和断点是LabVIEW调试的常用手段,该节以上一节的"测试耗时"为例 探针可以打在有线条的任何地方,打上后,经过这条线的所有最后一次的数值都会显示在探针窗口。断点可以打在程序框图的所有G代码对象,包括结构&#xf…

浅谈通信校验码及 CRC 校验

一、信息论中的 CRC 我上大学的时候,有一门课程叫做信息论,我就是从这个课程中学到的 CRC 校验这个词的,没错,当时学完整个课程后,CRC 对我来说依然只是一个单薄的缩写词语,全称我都不知道是啥。 CRC 全称是循环冗余校验(Cyclic Redundancy Check)。 说到信息论中的…

28. BI - 图论工具和算法, 社区发现以及最短路径

本文为 「茶桁的 AI 秘籍 - BI 篇 第 28 篇」 Hi, 我是茶桁. 咱们已经讲了好几节课的 PageRank, 也了解了 PageRank 的原理就是基于图论. 之前我有给讲过, 在「数学篇」中我们有用四个章节来详细的讲解图论的相关知识。其中包括: 23. 图论 - 图的由来和构成24. 图…

Go实现一个并发下载器

本文将实现一个并发的文件下载器,可以在不重新启动整个下载的情况下处理错误。这将通过分块下载文件来实现。 Idea 首先从发出下载的HTTP请求开始,当采用HEAD option来请求要下载的文件时,在某些服务器上,返回的标头之一是Conte…

【C++面向对象】C++考试题库管理系统(源码)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

构建第一个ArkTS应用(FA模型)

创建ArkTS工程 若首次打开DevEco Studio,请点击Create Project创建工程。如果已经打开了一个工程,请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发(本文以应用开发为例,Atomic Servi…

深入理解Java内存模型及其作用

目录 1.前言 2.为什么要有 Java 内存模型? 2.1 一致性问题 2.2 重排序问题 3.Java 内存模型的定义 4.规范内容 4.1 主内存和工作内存交互规范 4.2 什么是 happens-before 原则? 1.前言 当问到 Java 内存模型的时候,一定要注意&#…

【轻松上手】透明屏安装教程,一步到位,让您轻松享受透明视界

透明屏以其独特的视觉效果和广泛的应用场景,越来越受到人们的青睐。想要轻松享受透明视界,正确的安装步骤至关重要。下面,我们将为您提供一份简单明了的透明屏安装教程,让您一步到位,轻松上手。 第一步:准备…

STM32学习和实践笔记(4): 分析和理解GPIO_InitTypeDef GPIO_InitStructure (a)

深入分析及学习一下上面这一段代码的构成与含义。 首先,这个GPIO_InitTypeDef GPIO_InitStructure;其实与int a 是完全类似的语法格式以及含义。 GPIO_InitStructure就相当于a这样一个变量。不过从这个变量的名字可以知道,这是一个用于GPIO初始化的结构…