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总结 前言 目前在自动驾驶领域,比较火的一类研究方向是基于采集到的环视图像信息去构建BEV视角下的特征…...

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

在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的美妆购物系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、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 作为广泛应用的关系型数据库管理系统,创建数据库和表具有至关重要的意义。 在数据存储方面,数据库就如同一个巨大的仓库,为各类数据提供了安全、有序的存储环境。通过创建数据库,可以将相…...

大数据-126 - Flink State 03篇 状态原理和原理剖析:状态存储 Part1
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

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

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

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

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

Linux云计算 |【第三阶段】PROJECT1-DAY2
主要内容: 网站架构演变、LNPMariadb数据库分离、Web服务器集群(部署Nginx后端web服务器、部署NFS共享存储服务器、部署Haproxy代理服务器、部署DNS域名解析服务器) 一、网站架构演变: 随着网站访问量和业务复杂度的增加&#x…...

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

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

怎么看待伦敦银交易的风险与收益?
伦敦银交易的风险与收益,在宣传材料中,伦敦银是一种潜在收益很高,潜在风险不大的品种。然而在实践中我们发现,伦敦银交易好像并不如宣传材料说的那样容易做。那么,具体伦敦银交易的风险和收益是怎么样的?那…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...