当前位置: 首页 > 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;那…...

如何通俗易懂的解释TON的智能合约

文章目录 一、小故事一则二、Ton的智能合约在小故事中三、python代码模拟 一、小故事一则 在一个遥远的国度里&#xff0c;有一个被魔法笼罩的小镇&#xff0c;这个小镇每年都会举办一场盛大的戏剧节。这个戏剧节不仅是演员们展示才华的舞台&#xff0c;更是他们交流心得、共同…...

针对Docker容器的可视化管理工具—DockerUI

目录 ⛳️推荐 前言 1. 安装部署DockerUI 2. 安装cpolar内网穿透 3. 配置DockerUI公网访问地址 4. 公网远程访问DockerUI 5. 固定DockerUI公网地址 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…...

五大注入攻击网络安全类型介绍

1. SQL注入&#xff08;SQL Injection&#xff09; SQL注入流程 1.1. 概述 SQL注入是最常见的注入攻击类型之一&#xff0c;攻击者通过在输入字段中插入恶意的SQL代码来改变原本的SQL逻辑或执行额外的SQL语句&#xff0c;来操控数据库执行未授权的操作&#xff08;如拖库、获取…...

linux-L9.linux中对文件 按照时间排序 显示100 个

find . -type f -exec stat --format %Y %n {} | sort -nr | head -n 100解释&#xff1a; • find . -type f&#xff1a;在当前目录下查找所有文件。 • -exec stat --format ‘%Y %n’ {} &#xff1a;对每个找到的文件执行stat命令&#xff0c;以获取文件的修改时间&#…...

springboot从分层到解耦

注释很详细&#xff0c;直接上代码 三层架构 项目结构 源码&#xff1a; HelloController package com.amoorzheyu.controller;import com.amoorzheyu.pojo.User; import com.amoorzheyu.service.HelloService; import com.amoorzheyu.service.impl.HelloServiceA; import o…...

网络视频流解码显示后花屏问题的分析

问题描述 rtp打包的ps视频流发送到客户端后显示花屏。 数据分析过程 1、用tcpdump抓包 tcpdump -i eth0 -vnn -w rtp.pcap 2、用wireshark提取rtp的payload 保存为record.h264文件 3、用vlc播放器播放 显示花屏 4、提取关键帧 用xxd命令将h264文件转为txt文件 xxd -p…...

MySQL 大量 IN 的查询优化

背景 &#xff08;1&#xff09;MySQL 8.0 版本 &#xff08;2&#xff09;业务中遇到大量 IN 的查询&#xff0c;例&#xff1a; SELECT id, username, icon FROM users WHERE id IN (123, 523, 1343, ...);其中 id 为主键&#xff0c;IN 的列表长度有 8000 多个 问题 …...

python运维

环境准备 安装python3环境 # centos 安装python3 yum install python3创建激活venv python3 -m venv .venv source .venv/bin/activatezookeeper pip install kazoo 递归复制目录 from kazoo.client import KazooClientdef copy_node(zk, source_path, destination_path)…...

gen_server补充基础学习

学习gen_server的回调结构 gen_server:start_link(Name, Mod, InitArgs, Opts)这个调用是所有事物的起点。它 会创建一个名为Name的通用服务器&#xff0c;回调模块是Mod&#xff0c;Opts则控制通用服务器的行为。在这里可以指定消息记录、函数调试和其他行为。通用服务器通过…...

Python 入门教程(3)基础知识 | 3.1、基础语法

文章目录 一、 基础语法1、缩进规则2、标识符3、多行语句 一、 基础语法 1、缩进规则 学习 Python 与其他语言最大的区别就是&#xff0c;Python 的代码块不使用大括号 {} 来控制类&#xff0c;函数以及其他逻辑判断。python 最具特色的就是用缩进来写模块。缩进的空白数量是可…...