Redis 网络模型

一、用户空间和内核空间

1.1 linux 简介

        服务器大多采用 Linux 系统,这里我们以 Linux 为例来讲解,下面有两个不同的 linux 发行版,分别位 ubuntu centos,其实发行版就是在 Linux 系统上包了一层壳。

        任何 Linux 发行版,其系统内核都是 Linux。我们在 Linux 上安装的应用,比如说 mysqlredis 等,它们没有办法直接访问计算机硬件,它们需要先访问内核,然后再基于内核去操作计算机硬件。如下图:

        再细化的说下,计算机硬件一般包括 CPU、内存、网卡等各种各样的设备,虽然内核可以操作硬件,但它也需要不同设备的驱动,在设备驱动的基础上就可以形成对内存的管理、进程的管理、文件系统的管理和网络管理等等,如下图:

        最后呢,如果我们想让用户应用来访问,就必须在设备驱动的基础上封装一些接口,这样一来,我们的用户应用,包括一些依赖库等就可以调用这些接口,从而间接的实现对硬件设备的访问。

1.2 寻址空间

        但是这里有一个问题,我们的内核本质也是个应用,它在运行的过程中也需要一些 cpu 资源,内存资源等。所以为了避免用户应用导致冲突甚至内核崩溃,用户应用与内核是分离的。

        首先把进程的寻址空间划分为两部分:内核空间、用户空间。寻址空间是什么呢?其实无论是内核还是用户应用,都无法直接访问物理内存,而是给他们分配虚拟的内存空间,映射到不同的物理内存上,这样一来,我们的内核或者用户应用再去访问虚拟内存空间的时候就需要一个虚拟的地址了,这个地址是一个无符号的整数,从 0 开始,它的最大值取决于 cpu 的地址总线和寄存器的带宽,以一个 32 位系统为例,那么它的带宽一般为 32,因此它的地址的最大值就是 2^32 ,也就是说寻址的范围就是从 02^32,这个寻找的范围就是寻址空间。

        我们内存地址的每一个值代表的就是一个存储单元,也就是一个字节。所以 2^32 这么大的寻址空间最多代表的就是 2^32 字节,也即是 4GB,这也就是为什么一个 32 位的系统它的寻址空间最多就是 4GB 的原因。而这 4GB 又会被分为两部分,内核空间和用户空间。如下图:

        光在内存上做一个划分还不够,我们还需要在系统权限上做一个划分,因为在 cpu 运行的各种命令中,有一些命令的风险等级比较低,有一些比较高。

        用户空间只能执行受限的命令(Ring3),而且不能直接调用系统资源,必须通过内核提供的接口来访问。

        内核空间可以执行特权命令(Ring0),调用一切系统资源。

        一般来说用户的应用都是运行在用户空间,而内核的应用运行在内核空间。

         但是假设一个进程,执行的业务比较多,可能会执行一些普通的命令,也有可能需要去执行一些特权命令去调用系统资源,因此我们的进程就需要在用户空间和内核空间来回切换,当一个进程运行在用户空间的时候我们就称其为用户态,当期运行在内核空间的时候,就称其为内核态,如下图:

        所以我们的进程很有可能在两个状态之间进行切换,那么这个切换的流程到底是什么样子的呢?接下来举个 IO 读写的例子。

        Linux 系统为了提高 IO 效率,会在用户空间和内核空间都加入缓冲区:

        假设此时用户空间发起请求要去读数据,这个请求到达内核空间之后先去判断有没有数据,假如此时读取的是磁盘的数据,那么此时磁盘就需要去寻址,所以在这个过程中就需要等待;如果读取的不是磁盘的数据,读取的是网卡的数据,网卡的数据是别人传过来的,如果别人还没传过来,你还是需要等待的。所以当你发送一个读的请求时,首先是要等,等数据到达。数据到达之后,先把数据读取到缓冲区里面,然后把数据拷贝回用户空间里面做处理。

        其实影响我们 IO 效率最主要的第一个原因就是需要数据的等待,第二个原因是数据的拷贝,所以要想提高 IO 的效率,就需要从这两个点出发。减少无效的等待和减少用户态和内核态之间缓冲区的拷贝。后面的五种不同的 IO 模型都是针对这两个点进行优化的。

二、阻塞 IO

        顾名思义,阻塞 IO 就是两个阶段都必须阻塞等待。这个过程需要经历两个阶段。

阶段一:

        1、用户进程尝试读取数据(比如网卡数据)

        2、此时数据尚未到达,内核需要等待数据

        3、此时用户进程也处于阻塞状态

阶段二:

        1、数据到达并拷贝到内核缓冲区,代表已就绪

        2、将内核数据拷贝到用户缓冲区

        3、拷贝过程中,用户进程依然阻塞等待

        4、拷贝完成,用户进程解除阻塞,处理数据

        可以看到,阻塞 IO 模型中,用户进程在两个阶段都是阻塞状态。

三、非阻塞 IO

        顾名思义,非阻塞 IOrecvfrom 操作会立即返回结果而不是阻塞用户进程。这个过程需要经历两个阶段。

阶段一:

        1、用户进程尝试读取数据(比如网卡数据)

        2、此时数据尚未到达,内核需要等待数据

        3、返回异常给用户进程

        4、用户进程拿到 error 后,再次尝试读取

        5、循环往复,直到数据就绪

阶段二:

        1、将内核数据拷贝到用户缓冲区

        2、拷贝过程中,用户进程依然阻塞等待

        3、拷贝完成,用户进程解除阻塞,处理数据

        可以看到,非阻塞 IO 模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高。而且忙等机制会导致 CPU 空转,CPU 使用率暴增。 

四、IO 多路复用

4.1 简介

        无论是阻塞 IO 还是非阻塞 IO,用户应用在一阶段都需要调用 recvfrom 来获取数据,差别在于无数据时的处理方案:

        1、如果调用 recvfrom 时,恰好没有数据,阻塞 IO 会使 CPU 阻塞,非阻塞 IO 使 CPU 空转,都不能充分发挥 CPU 的作用。

        2、如果调用 recvfrom 时,恰好有数据,则用户进程可以直接进入第二阶段,读取并处理数据。

        而在单线程情况下,只能依次处理 IO 事件,如果正在处理的 IO 事件恰好未就绪(数据不可读或不可写),线程就会被阻塞,所有 IO 事件都必须等待,性能自然会很差。

上面的情况就比如服务员给顾客点餐,分两步:

        1、顾客思考要吃什么(等待数据就绪)

        2、顾客想好了,开始点餐(读取数据)

        要提高效率有两种办法,第一种增加更多服务员(多线程)。第二种是不排队,谁想好了吃什么(数据就绪了),服务员就给谁点餐(用户应用就去读取数据)。那么用户进程如何知道内核中数据是否就绪呢?此时就需要用到 FD 了。

4.2 文件描述符 FD

        文件描述符(File Descriptor):简称 FD,是一个从 开始的无符号整数,用来关联 Linux 中的一个文件。在 Linux 中,一切皆文件,例如常规文件、视频、硬件设备等,当然也包括网络套接字(Socket)。

        IO 多路复用:是利用单个线程来同时监听多个 FD,并在某个 FD 可读、可写时得到通知,从而避免无效的等待,充分利用 CPU 资源。也是分为两个阶段:

阶段一:

        1、用户进程调用 select,指定要监听的 FD 集合。

        2、内核监听 FD 对应的多个 socket

        3、任意一个或多个 socke t数据就绪则返回 readabl

        4、此过程中用户进程阻塞

阶段二:

        1、用户进程找到就绪的 socket

        2、依次调用 recvfrom 读取数据

        3、内核将数据拷贝到用户空间

        4、用户进程处理数据

        IO 多路复用是利用单个线程来同时监听多个 FD,并在某个 FD 可读、可写时得到通知,从而避免无效的等待,充分利用 CPU 资源。不过监听 FD 的方式、通知的方式又有多种实现,常见的有:selectpollepoll。它们之间的差异如下:

        1、select poll 只会通知用户进程有 FD 就绪,但不确定具体是哪个 FD,需要用户进程逐个遍历 FD 来确认。

        2、epoll 则会在通知用户进程 FD 就绪的同时,把已就绪的 FD 写入用户空间。

五、信号驱动 IO

        信号驱动 IO 是与内核建立 SIGIO 的信号关联并设置回调,当内核有 FD 就绪时,会发出 SIGIO 信号通知用户,期间用户应用可以执行其它业务,无需阻塞等待。这个过程可以分为两个阶段。

阶段一:

        1、用户进程调用 sigaction,注册信号处理函数

        2、内核返回成功,开始监听 FD

        3、用户进程不阻塞等待,可以执行其它业务

        4、当内核数据就绪后,回调用户进程的 SIGIO 处理函数

阶段二:

        1、收到 SIGIO 回调信号

        2、调用 recvfrom,读取数据。

        3、内核将数据拷贝到用户空间

        4、用户进程处理数据

        当有大量 IO 操作时,信号较多,SIGIO 处理函数不能及时处理可能导致信号队列溢出,而且内核空间与用户空间的频繁信号交互性能也较低。

六、异步 IO

        异步 IO 的整个过程都是非阻塞的,用户进程调用完异步 API 后就可以去做其它事情,内核等待数据就绪并拷贝到用户空间后才会递交信号,通知用户进程。整个过程分为两个阶段。

阶段一:

        1、用户进程调用 aio_read,创建信号回调函数

        2、内核等待数据就绪

        3、用户进程无需阻塞,可以做任何事情

阶段二:

        1、内核数据就绪

        2、内核数据拷贝到用户缓冲区

        3、拷贝完成,内核递交信号触发 aio_read 中的回调函数

        4、用户进程处理数据

        可以看到,异步 IO 模型中,用户进程在两个阶段都是非阻塞状态。

七、同步还是异步

        IO 操作是同步还是异步,关键看数据在内核空间与用户空间的拷贝过程(数据读写的 IO 操作),也就是阶段二是同步还是异步:

八、Redis 网络模型

8.1 Redis 是否为单线程

Redis 到底是单线程还是多线程?

        1、如果仅仅聊 Redis 的核心业务部分(命令处理),答案是单线程。

        2、如果是聊整个 Redis,那么答案就是多线程。

Redis 版本迭代过程中,在两个重要的时间节点上引入了多线程的支持

        1、Redis v4.0:引入多线程异步处理一些耗时较旧的任务,例如异步删除命令 unlink

        2、Redis v6.0:在核心网络模型中引入多线程,进一步提高对于多核 CPU 的利用率。

        因此,对于 Redis 的核心网络模型,在 Redis 6.0 之前确实都是单线程。是利用 epollLinux 系统)这样的 IO 多路复用技术在事件循环中不断处理客户端情况。

为什么 Redis 要选择单线程?

        1、抛开持久化不谈,Redis 是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,因此多线程并不会带来巨大的性能提升。

        2、多线程会导致过多的上下文切换,带来不必要的开销

        3、引入多线程会面临线程安全问题,必然要引入线程锁这样的安全手段,实现复杂度增高,而且性能也会大打折扣。

8.2 Redis 网络模型

        Redis 6.0 版本中引入了多线程,目的是为了提高 IO 读写效率。因此在解析客户端命令、写响应结果时采用了多线程。核心的命令执行、IO 多路复用模块依然是由主线程执行。如下图:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RS-232协议详解:深入理解与实际应用

RS-232协议详解 RS-232协议,也称为推荐标准232,是一种用于串行通信的标准协议。它在计算机和外围设备之间的通信中广泛应用。本文将详细介绍RS-232协议的各个方面,包括其历史、工作原理、信号类型、连接方式、应用场景等。希望通过这篇文章&a…

如何使用React的lazy和Suspense来实现代码分割?

在React中,使用React.lazy和Suspense可以方便地实现组件的代码分割。代码分割是一种优化技术,它将代码拆分成多个包,然后按需加载这些包,从而加快应用的初始加载时间。下面是如何使用这两个API的基本步骤: 使用React.l…

软考初级网络管理员__网络单选题

1.某人的电子邮箱为 Rjspks163.com,对于Rjspks和163.com的正确理解为(2),在发送电子邮件时,常用关键词使用中,(3)是错误的,采用的协议是(4)。若电子邮件出现字符乱码现象,以下方法中(5)一定不能解决该问题。 SNMP SM…

【安防天下】模拟视频监控系统——模拟监控系统的构成视频采集设备

文章目录 1 模拟监控系统的构成2 视频采集设备2.1 摄像机相关技术2.1.1 摄像机的工作原理2.1.2 摄像机的分类2.1.3 摄像机的主要参数 2.2 镜头相关介绍2.2.1 镜头的主要分类2.2.2 镜头的主要参数 1 模拟监控系统的构成 模拟视频监控系统又称闭路电视监控系统, 一般…

DB9母头接口定义485

在通信技术中,DB9接口广泛应用于串行通信,尤其是在RS232和RS485标准中。虽然DB9接口最常见于RS232通信,但通过适当的引脚映射,它也可以用于RS485通信。本文将详细介绍如何定义和使用DB9母头接口进行RS485连接。 DB9母头接口简介 …

这些帮助你成长的IOS应用,建议收藏

TrackIt TrackIt是一款功能丰富的任务清单、日程管理和习惯打卡应用,旨在帮助用户提高效率和专注力。通过这些功能,用户可以更好地规划时间和任务,从而实现个人目标和养成良好习惯。 在目标设定方面,SMART原则是一个常用的方法&a…

数据可视化实验五:seaborn绘制进阶图形

目录 一、绘制动态轨迹图 1.1 代码实现 1.2 绘制结果 二、使用seaborn绘制关系图 2.1 绘制散点图分析产品开发部已离职的员工的评分与平均工作时间 2.1.1 代码实现 2.1.2 绘制结果 ​编辑 2.2 基于波士顿房价数据,绘制房间数和房屋价格的折线图 2.2.1 代码…

redis 缓存jwt令牌设置更新时间 BUG修复

大家好,今天我又又又来了,hhhhh。 上文中 我们永redis缓存了token 但是我们发现了 一个bug ,redis中缓存的token 是单用户才能实现的。 就是 我 redis中存储的键 名 为token 值 是jwt令牌 ,但是如果 用户a 登录 之后 创建一个…

区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测

区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测 目录 区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测效果一览基本介绍程序设计参考资…

【Ubuntu通用压力测试】Ubuntu16.04 CPU压力测试

使用 stress 对CPU进行压力测试 我也是一个ubuntu初学者,分享是Linux的优良美德。写的不好请大佬不要喷,多谢支持。 sudo apt-get update 日常先更新再安装东西不容易出错 sudo apt-get upgrade -y 继续升级一波 sudo apt-get install -y linux-tools…

【尚庭公寓SpringBoot + Vue 项目实战】移动端登录管理(二十)

【尚庭公寓SpringBoot Vue 项目实战】移动端登录管理(二十) 文章目录 【尚庭公寓SpringBoot Vue 项目实战】移动端登录管理(二十)1、登录业务2、接口开发2.1、获取短信验证码2.2、登录和注册接口2.3、查询登录用户的个人信息 1、…

后端学习笔记:Python基础

后端学习笔记:Python基础 数据类型: Python中主要有以下几种常用的基本数据类型: String 字符串类型,用单引号或者双引号引用Number 数字类型,包括浮点数,整数,长整数和复数List 列表项&…

ENVI实战—一文搞定非监督分类

实验1:使用isodata法分类 目的:学会使用isodata法开展非监督分类 过程: ①导入影像:打开ENVI,按照“文件→打开为→光学传感器→ESA→Sentinel-2”的顺序,打开实验1下载的哨兵2号数据。 图1 ②区域裁剪…

Hbase搭建教程

Hbase搭建教程 期待您的关注 ☀小白的Hbase学习笔记 目录 Hbase搭建教程 1.上传hbase的jar包并解压 2.重新登录 3.启动zookeeper 4.配置环境变量 5.关闭ZK的默认配置 6.修改hbase-site.xml文件 7.修改regionservers文件 8.将配置好的文件分发给其它节点 9.配置环境变量…

PyCharm新手入门

前言 在之前《Python集成开发工具的选择》一文中介绍了python初学者可以使用Jupyter Notebook,Jupyter Notebook简单易用,可以用来练习代码编写,但是实际生产开发环境使用这个工具是远远不够用的,因为实际软件开发中需要软件调试…

LabVIEW程序闪退问题

LabVIEW程序出现闪退问题可能源于多个方面,包括软件兼容性、内存管理、代码质量、硬件兼容性和环境因素。本文将从这些角度进行详细分析,探讨可能的原因和解决方案,并提供预防措施,以帮助用户避免和解决LabVIEW程序闪退的问题。 1…

软考高级论文真题“论大数据lambda架构”

论文真题 大数据处理架构是专门用于处理和分析巨量复杂数据集的软件架构。它通常包括数据收集、存储、处理、分析和可视化等多个层面,旨在从海量、多样化的数据中提取有价值的信息。Lambda架构是大数据平台里最成熟、最稳定的架构,它是一种将批处理和流…

前端锚点 点击 滑动双向绑定

一. 页面样式 二. 代码 <div class"flexBox"><div class"mdDiv" v-for"(item,index) in tabList" :key"index" :class"nowChooseindex?choosed:" click"jumpMD(index, item.id)">{{item.name}}&l…

C++ 实现HTTP的客户端、服务端demo和HTTP三方库介绍

本文使用C模拟实现http的客户端请求和http的服务端响应功能&#xff0c;并介绍几种封装HTTP协议的三方库。 1、实现简单HTTP的服务端功能 本程序使用C tcp服务端代码模拟HTTP的服务端&#xff0c;服务端返回给客户端的消息内容按照HTTP协议的消息响应格式进行了组装。 demo如…

Apipost模拟HTTP客户端

目录 APIFOX的站内下载&#xff1a; Apipost模拟HTTP客户端&#xff08;正文&#xff09; 新建窗口 添加服务器地址、头信息介绍 添加请求体 发送以及返回状态 模拟HTTP客户端的软件有很多&#xff0c;其中比较著名的就有API-FOX、POSTMAN。 相信很多小伙伴都使用POSTMAN…