当前位置: 首页 > news >正文

Redis网络模型、通信协议、内存回收

Redis网络模型

  • 一、用户空间和内核空间(前提)
      • 问题来了:为啥要区分用户空间和内核空间呢?
      • 我们来看看两个空间以及硬件是如何操作的
  • 二、Linux中五种IO模型
    • 1、 阻塞IO
    • 2、非阻塞IO
    • 3、IO多路复用
      • 3.1、SELECT
      • 3.2、poll
      • 3.3、epoll
    • 4、信号驱动IO
    • 5、异步IO
  • 三、Redis中的网络模型
  • 四、Redis通信协议
    • 定义
    • RESP2协议-数据类型
  • 五、Redis内存回收

一、用户空间和内核空间(前提)

在这里插入图片描述
我们知道操作系统采用的是虚拟地址空间,以32位操作系统举例,它的寻址空间为4G(2的32次方),这里解释二个概念:
寻址: 是指操作系统能找到的地址范围,32位指的是地址总线的位数,你就想象32位的二进制数,每一位可以是0,可以是1,是不是有2的32次方种可能,2^32次方就是可以访问到的最大内存空间,也就是4G。
虚拟地址空间: 为什么叫虚拟,因为我们内存一共就4G,但操作系统为每一个进程都分配了4G的内存空间,这个内存空间实际是虚拟的,虚拟内存到真实内存有个映射关系。例如X86 cpu采用的段页式地址映射模型。
操作系统将这4G可访问的内存空间分为二部分,一部分是内核空间,一部分是用户空间
内核空间是操作系统内核访问的区域,独立于普通的应用程序,是受保护的内存空间
用户空间是普通应用程序可访问的内存区域。
以linux(32位操作系统)为例:
将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间
在这里插入图片描述
每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。

问题来了:为啥要区分用户空间和内核空间呢?

其实早期操作系统是不区分内核空间和用户空间的,但是应用程序能访问任意内存空间,如果程序不稳定常常把系统搞崩溃,比如清除操作系统的内存数据。后来觉得让应用程序随便访问内存太危险了,就按照CPU 指令的重要程度对指令进行了分级,指令分为四个级别:Ring0~Ring3 (和电影分级有点像),linux 只使用了 Ring0 和 Ring3 两个运行级别,进程运行在 Ring3 级别时运行在用户态,指令只访问用户空间,而运行在 Ring0 级别时被称为运行在内核态,可以访问任意内存空间。
用户态的程序不能随意操作内核地址空间,这样对操作系统具有一定的安全保护作用。

我们来看看两个空间以及硬件是如何操作的

在这里插入图片描述
**写数据到磁盘:**首先将数据写到用户空间的缓冲区,然后调用内核,内核则将数据从空间缓冲区copy到内核缓冲区,然后再将缓冲区中的数据写入磁盘。
从网络中或者磁盘中读数据 :进程首先切换到内核态,调用内核从网卡或者磁盘中读,但是没有的时候就需要等待,有则将数据读到内核的缓冲区再copy到用户区使用。
其实这里就有很多空间进行IO优化了,比如没有数据读的时候需要一直等待(一直占用cpu资源),以及读写的多次拷贝(两个空间的来回切换)等等。

二、Linux中五种IO模型

1、 阻塞IO

顾名思义:没有数据的时候一直等待,有数据则拷贝到用户空间进行处理。
在这里插入图片描述

2、非阻塞IO

顾名思义:没有就返回错误,但是会一直请求,花里胡哨其实一点用也没有,用户还是停留在访问等待直到有数据(盲目等待),拷贝到用户空间进行处理。
注意:由于没有数据的时候一直访问,cpu一直执行指令可能性能更低(cpu空转),甚至不如阻塞IO。
在这里插入图片描述

3、IO多路复用

看到这里大家发现,其实不管阻塞IO还是非阻塞IO,第一阶段都需要等待数据(恰好没数据),但是当多个进程来时,等待会影响整个业务,下面用个生活中的例子来表示,排队点餐。
在这里插入图片描述
如果第一顾客还没想好自己要吃啥的时候,后面的顾客都需要等待(等待数据)
如果已经想好了,开始点餐(读取数据)
那我们如何提高点单速率呢?

  • 多加几个前台(多线程)
  • 不排队,谁想好了吃啥,服务员就先给谁点单(读数据)

显然第二种更好一点,不需开多线程去提高效率。

问题又来了:如何知道顾客已经想好了(数据就绪?)
这里需要了解一个概念-文件描述符(File Decriptor)简称FD,是一个从0开始的无符号整数(自然数),用来关联Linux中的一个文件。在Linux中一切皆文件,常规文件,视频,硬件等待,当然包括网络套接字(Socket)。
IO多路复用: 是利用单线程来同时监听多个FD,并且在某个FD可读、可写时得到通知,从而避免无效的等待,充分利用了CPU的资源。
在这里插入图片描述
在等待数据方面,用户调用select方法,同时监听多个FD,如果都没有数据则等待(也就是所有顾客都没有想好吃啥)这个时候才阻塞等待,当有一个想好了,就可以进行点餐。从而避免了没有数据的时候直接调用recvfrom函数去内核空间中等待,浪费cpu资源。

那我们再深一层解析一下监听和通知
方式有三种 一个是上面说的select 还有poll 和epoll 他们有啥区别吗?
依旧使用前面的生活案例来解释:
在这里插入图片描述
select和poll: 当有顾客想好了,然后通知给点单前台,但是前台是不知道具体哪一位顾客准备好了,然后就一个一个问顾客(遍历),找到了再进行点单。
其实他的缺点也看到了就是有人下单了,无法立即确定是哪一个顾客。
epoll: 有一个顾客想好后,会显示到点单员电脑上,直接下单准备食物即可。
转换成计算机的话:

  • select和poll:只会通知用户进程有FD就绪,但是不确定是哪一个FD,需要逐个遍历FD来确定
  • epoll :则会通知用户进程FD就绪的同时,把已就绪FD写入用户空间中。更高效

3.1、SELECT

上源码:
在这里插入图片描述
本质是数组存二进制位,0表示未就绪,1则表示就绪,共有三个,一个是监听读事件,一个写数件,还一个是异常事件(1024位)。
select函数同时监听这三者的状态。
流程如图(假设8个位置)我们假设监听FD为1,2,5。
在这里插入图片描述
过程: 执行select函数,需要内核空间帮我监听,拷贝数组到内核空间,遍历数组,没有则休眠,有则唤醒,并且传回用户空间(又将数组拷贝回去),然后用户空间再遍历一次找到相关的就绪FD。
不足:

  • 执行select需要拷贝一份到内核空间,监听完之后又要拷贝一份到用户空间(一次监听就要2次切换),在监听后续的fd又需要重复以上操作。
  • 内核空间监听需要遍历整个数组,监听到返回给用户空间又要遍历一遍数组查找就绪fd(两次遍历)
  • 大小不能超过1024,若超过需要修改源码(很麻烦)

3.2、poll

直接上源码
在这里插入图片描述
其实和select的数据结构差不多只是数组中添加了一个状态,从而无需三个数组(换汤不换药)

执行流程:
1、创建数组pollFD,添加监听的fd信息,数组大小自定义
2、调用poll函数,将数组拷贝到内核空间,转链表存储(无上限)
3、内核遍历,判断是否就绪
4、数据就绪或者超时后,拷贝数组到用户空间,返回就绪数量n
5、使用进程判断n大于零就开始遍历数组找就绪的fd
其实本质和select没啥区别,只不过数组自定义可以大于1024个fd同时监听,内核中采用链表存储,再一个fd越多遍历越慢,性能反而下降。(意义不大,所以很少使用这种方式)

3.3、epoll

上源码
在这里插入图片描述
底层结构和过程:本质是由一个红黑树和一个链表组成,调用创建函数(epoll_create)创建并且返回,epoll_ctl()函数将fd加入到红黑树中(监听作用)并且设置回调函数,一旦回调函数触发就将该fd添加到链表(list_head)中,再通过epoll_wait()函数检查链表,有则返回就绪fd数量,并且将链表中fd复制到events数组中给用户空间使用。
在这里插入图片描述
我们将之前select的不足截取过来对比:
在这里插入图片描述

最后总结: 我们来看看相对前面二者的不足,epoll做了啥优化。

  • 对于解决监听上限的问题:基于epoll是使用红黑树存储fd,理论上数据可以很大而且红黑树查询性能不受很大的影响。
  • 对于每次监听都需要将数组拷贝到内核空间:epoll只需要执行一次epoll_ctl()就将所有fd存入红黑树中,以后每次添加fd元素即可,在等待就绪时函数epoll_wait()无需传参,无需重新拷贝fd数组到内核空间。
  • 对于将就绪的fd拷贝回用户空间:epoll无需遍历所有数组去找就绪的,而是返回的都是就绪的。

4、信号驱动IO

是与内核简历sigIO的信号关联并且设置回调,当有fd就绪就会发出sigIO信号通知用户,期间用户可以执行其他业务,无需阻塞等待。
在这里插入图片描述
特点:可以看到在等待数据阶段,是直接交给内核空间用户空间不管的
这里需要和非阻塞IO区分,等待阶段非阻塞IO是一直询问有木有数据(本质还是阻塞)
为啥我们不使用他呢?(有啥缺点?)

  • 在大量IO操作的时候,信号较多,sigIO函数不能及时处理可能导致信号队列溢出
  • 内核空间和用户空间的频繁信号交互性能也较低

5、异步IO

整个过程都是非阻塞的,用户进程调用完异步API就去做别的事情,数据等待和拷贝都是异步执行(一条龙服务)。
在这里插入图片描述
使用相对多一点,但是还是有个缺点:如果io多了,内核IO性能不是很高,导致内存消耗过多导致整个崩溃(就像老板一直把事情交给你,不管你死活)

总结:
前四种IO都是同步IO,只有最后一个是异步IO(以数据拷贝是否阻塞为基准)
在这里插入图片描述

三、Redis中的网络模型

在这里插入图片描述
简单解释:
底层就是使用IO多路复用+事件派发,首先是服务端可读,连接应答处理器将客户端socket(FD)注册到IO多路复用程序,进行客户端的读写监听,当客户端需要操作(就绪) 时(也就是客户端可读),会使用命令请求处理器,首先将请求的数据(Redis6.0前是单线程,之后引入多线程)写入缓冲区,再将数据转化为redis命令并且执行,将返回值写入缓冲区,当多个操作后就将多个client写入队列,再通过遍历队列绑定命令回复处理器,Redis6.0之前是单线程逐个处理,之后引进多线程提升了回复效率。

引入多线程: 对于redis来说在监听fd,以及命令执行的时候,(主线程)单线程是完成足够的(纯内存),真正影响性能的永远是IO,就是读命名和回复响应值(来回的拷贝)占用网络资源。

四、Redis通信协议

定义

Redis是一个CS架构软件,通信一般分两步:

  • 客户端(Client)向服务端(Server)发生一条命令。
  • 服务端解析并且执行命令,返回响应结果给客户端。

因此二者之间数据交互需要有个格式规范,这个规范就是通信协议。
而Redis中采用的就是RESP(Redis Serialization Protocol)协议

  • Redis1.2版本引入该协议
  • Redis2.0版本成为标准,称为RESP2
  • Redis6.0版本升级为RESP3,增加了更多的新数据类型和特性–客户端缓存

但目前默认使用的是RESP2,也是我们下面学习的。

RESP2协议-数据类型

通过首字节的字符来区分不同的数据类型,常用的包括5种:

  • 单行字符串:首字节是‘ +’,后面跟上单行字符串,以(“\r\n”)结尾。如:“ok” :“+ok\r\n”

  • 错位(Error):首字母‘-’,与单行字符串一样,只不过是错误信息。如:“-Error Message\r\n”

  • 数值:首字节为‘:’,后面跟上数字格式字符串也是(“\r\n”)结尾。如:“:10\r\n”

  • 多行字符串:首字节为“$”,表示二进制安全(本质和SDS一样,记录字符串占用字节大小,内容中存在"\r\n"也没事),最大支持521MB
    在这里插入图片描述
    在这里插入图片描述

  • 数组:首字节是 *,后面跟上数组元素个数,在跟上元素,类型不限(中文3个字节)
    在这里插入图片描述

五、Redis内存回收

参考我另一篇文章–《redis面试篇》中的过期策略和淘汰策略

相关文章:

Redis网络模型、通信协议、内存回收

Redis网络模型 一、用户空间和内核空间(前提)问题来了:为啥要区分用户空间和内核空间呢?我们来看看两个空间以及硬件是如何操作的 二、Linux中五种IO模型1、 阻塞IO2、非阻塞IO3、IO多路复用3.1、SELECT3.2、poll3.3、epoll 4、信…...

闯关leetcode——21. Merge Two Sorted Lists

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/merge-two-sorted-lists/description/ 内容 You are given the heads of two sorted linked lists list1 and list2. Merge the two lists into one sorted list. The list should be made by sp…...

Notepad++中提升编码效率的关键快捷键

基本操作 Ctrl N:新建文件。Ctrl O:打开文件。Ctrl S:保存文件。Ctrl Shift S:另存为。Ctrl W:关闭当前文件。 文件和标签管理 Ctrl Tab:切换到下一个标签。Ctrl Shift Tab:切换到上…...

ai智能语电销机器人有哪些功能?

近几年火爆的AI语音机器人,已经可以成熟的服务于金融贷款、理财、房地产、电商、汽车等行业,成熟的适用于电话销售、客服服务、售后管理等等基础岗位,那么ai智能语电销机器人有哪些功能?我们来看一看。 顾名思义,智能…...

ctfshow-PHP反序列化

web254 源码 <?php/* # -*- coding: utf-8 -*- # Author: h1xa # Date: 2020-12-02 17:44:47 # Last Modified by: h1xa # Last Modified time: 2020-12-02 19:29:02 # email: h1xactfer.com # link: https://ctfer.com //mytime 2023-12-4 0:22 */ error_reporting(0)…...

BEV学习---LSS-2

前言一、相关参数设置二、LSS算法前向过程 1.整体步骤2.创建视锥3.坐标变换4.视锥点云特征5.VoxelPooling 5.1 cumsum_trick(池化累积求和技巧):5.2 VoxelPooling总结 前言 目前在自动驾驶领域&#xff0c;比较火的一类研究方向是基于采集到的环视图像信息去构建BEV视角下的特征…...

PhpStudy下载安装使用学习

一、官网下载 官网地址&#xff1a;Windows版phpstudy下载 - 小皮面板(phpstudy)https://old.xp.cn/download.html 【首页】选择Windows版&#xff0c;进行下载 下载完成是一个压缩包的形式&#xff0c;解压得到一个.exe的执行文件&#xff0c;点击执行安装程序&#xff08;注…...

在Excel中通过Python运行公式和函数实现数据计算

目录 一、引言 1.1 背景介绍 1.2 Python in Excel 的意义 二、环境准备 2.1 安装必要的软件 2.2 配置 Excel 三、基础操作 3.1 输入 Python 代码 3.2 调用 Python 库 四、案例分析 4.1 数据读取与处理 4.1.1 读取 Excel 数据 4.1.2 数据处理 4.2 数据可视化 4.2…...

基于SpringBoot+Vue的美妆购物系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…...

uniapp uni-table合并单元格

视图层 <uni-table border stripe emptyText"暂无更多数据" class"table_x"><!-- 表头行 --><uni-tr><uni-th align"center">患者姓名</uni-th><uni-th align"center">透析方式</uni-th>&…...

MySQL 创建数据库和表全攻略

一、MySQL 创建数据库与表的重要性 MySQL 作为广泛应用的关系型数据库管理系统&#xff0c;创建数据库和表具有至关重要的意义。 在数据存储方面&#xff0c;数据库就如同一个巨大的仓库&#xff0c;为各类数据提供了安全、有序的存储环境。通过创建数据库&#xff0c;可以将相…...

大数据-126 - Flink State 03篇 状态原理和原理剖析:状态存储 Part1

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…...

RFID射频模块(MFRC522 STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.工作原理介绍 三、程序设计 main.c文件 MFRC522.h文件 MFRC522.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 RC522 RFID射频模块是一款广泛应用于非接触式RFID系统中的核心组件&#xff0c;由NXP&…...

【JavaSE】--方法的使用

文章目录 1. 方法概念及使用1.1 什么是方法1.2 方法定义1.3 方法调用的执行过程1.4 实参和形参的关系&#xff08;重要&#xff09;1.5 没有返回值的方法 2. 方法重载2.1 方法重载概念2.2 方法签名 3. 递归3.1 递归的概念3.2 递归执行过程分析3.3 递归练习 1. 方法概念及使用 1…...

wireshark打开时空白|没有接口,卸载重装可以解决

解决方法&#xff1a;卸载wireshark,全选卸载干净&#xff0c;重新安装旧版的wireshark4.2.7, 甚至cmd下运行net start npf时显示服务名无效&#xff0c;但打开wireshark仍有多个接口 错误描述&#xff1a; 一开始下载的是wireshark的最新版&#xff0c;win11 x64 在安装wir…...

单值二叉树--(C语言)

题目如下&#xff1a; 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时&#xff0c;才返回 true&#xff1b;否则返回 false。 示例 1&#xff1a; 输入&#xff1a;[1,1,1,1,1,null,1] 输出&#xff1a;true示例 2&a…...

Linux云计算 |【第三阶段】PROJECT1-DAY2

主要内容&#xff1a; 网站架构演变、LNPMariadb数据库分离、Web服务器集群&#xff08;部署Nginx后端web服务器、部署NFS共享存储服务器、部署Haproxy代理服务器、部署DNS域名解析服务器&#xff09; 一、网站架构演变&#xff1a; 随着网站访问量和业务复杂度的增加&#x…...

Claude Prompt 汉语新解

感谢刚哥&#xff01; ;; 作者: 李继刚 ;; 版本: 0.3 ;; 模型: Claude Sonnet ;; 用途: 将一个汉语词汇进行全新角度的解释 ​ ;; 设定如下内容为你的 *System Prompt* (defun 新汉语老师 () "你是年轻人,批判现实,思考深刻,语言风趣" (风格 . ("Oscar Wilde&q…...

【运维监控】influxdb 2.0+grafana 监控java 虚拟机以及方法耗时情况(2)

运维监控系列文章入口&#xff1a;【运维监控】系列文章汇总索引 文章目录 四、grafana集成influxdb监控java 虚拟机以及方法耗时情况1、添加grafana数据源2、添加grafana的dashboard1&#xff09;、选择新建dashboard方式2&#xff09;、导入dashboard 3、验证 关于java应用的…...

怎么看待伦敦银交易的风险与收益?

伦敦银交易的风险与收益&#xff0c;在宣传材料中&#xff0c;伦敦银是一种潜在收益很高&#xff0c;潜在风险不大的品种。然而在实践中我们发现&#xff0c;伦敦银交易好像并不如宣传材料说的那样容易做。那么&#xff0c;具体伦敦银交易的风险和收益是怎么样的&#xff1f;那…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

实战三:开发网页端界面完成黑白视频转为彩色视频

​一、需求描述 设计一个简单的视频上色应用&#xff0c;用户可以通过网页界面上传黑白视频&#xff0c;系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观&#xff0c;不需要了解技术细节。 效果图 ​二、实现思路 总体思路&#xff1a; 用户通过Gradio界面上…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

Yii2项目自动向GitLab上报Bug

Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...