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.mzph.cn/bicheng/28801.shtml

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

相关文章

Draw.io

Draw.io Draw.io是一款很实用的思维导图软件,现在已经推出了桌面版,对于很多办公人士而言画张流程图可以轻松的罗列整个流程,比使用文字或者幻灯片制作简单并且容易理解,该应用程序不仅免费,还拥有专业的工具&#xf…

详细图文手把手教你阿里云注册域名如何托管到CloudFlare DNS服务

1.第一步:注册并登录Cloudflare账号,点击右上角“添加站点”,进入下图页面填写域名,点击继续。 2.第二步:进入页面滑动到最下方,选择Free免费套餐,再次点击继续。 3.第三步:这个页面…

基于starknet构建应用链之Madara

文章目录 什么是Madara应用链模板其他仓库为何要构建应用链?什么是Madara 欢迎来到Madara,使用Cairo和Starknet技术构建链的模块化堆栈。像dYdX V3、Immutable和Sorare这样的应用程序已经使用StarkEx进行扩展有一段时间了,现在有了Madara,它是开源的,每个人都可以使用。 …

c# 二维图形绘制实践

1.等边三角形 1.1 概述 1.2 代码 using System; using System.Drawing; using System.Windows.Forms;public partial class TriangleForm : Form {public TriangleForm(){//InitializeComponent();// 确保窗体大小足够大,以容纳三角形 this.ClientSize new Siz…

AbMole带你探索细胞的“铁”门:Piezo1通道在椎间盘退变中的关键角色

在生物医学领域,铁是细胞功能不可或缺的元素,但铁的异常积累却可能成为细胞的“隐形杀手”。最近,一项发表在《Bone Research》上的研究,为我们揭开了铁代谢与椎间盘退变之间神秘联系的一角。这项研究不仅深化了我们对铁离子通道P…

5个超实用1688选品技巧!轻松出单999+

1、研究市场需求 通过市场调查和分析,了解目标市场的消费者喜好和趋势。选择具有市场需求且竞争相对较小的产品类别。 用店雷达热销商 品榜和飙升商 品榜。比如做女装类目,选择“女士T恤”我们可以根据日、周、月为时间维度下商品的销售笔数、件数、销…

Browserslist: caniuse-lite is outdated。浏览器列表:caniuse lite已经过时???

一、最近运行项目启动时提示 Browserslist: caniuse-lite is outdated. Please run: npx update-browserslist-dblatest Why you should do it regularly: https://github.com/browserslist/update-db#readme 这要是这一句,Browserslist: caniuse-lite is outdated.…

大神出新品,吴恩达开源机器翻译智能体项目

节前,我们星球组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

走近科学之《netty 的秘密》

Approaching science《the secret of netty》 IO 相关概念、五种 IO 模型、BIO NIO AIO 特点及区别、NIO 设计原理及核心组件、netty 简介及应用场景、netty 线程模型(Reactor 线程模型)、netty 设计原理及核心组件、netty 常用技巧实现(心跳…

Django REST framework序列化器详解:普通序列化器与模型序列化器的选择与运用

系列文章目录 Django入门全攻略:从零搭建你的第一个Web项目Django ORM入门指南:从概念到实践,掌握模型创建、迁移与视图操作Django ORM实战:模型字段与元选项配置,以及链式过滤与QF查询详解Django ORM深度游&#xff…

【unity笔记】二、海洋系统Crest Ocean System基础

1. 创建海平面 首先确定项目中导入了HDRP插件。这里使用Crest Ocean System HDRP插件。 在场景下创建空对象,这里命名为Ocean。将 OceanRenderer 组件分配给Ocean。该组件将生成海洋几何图形并执行所有必需的初始化。其中Global Wind Speed 属性可以调节风浪大小。…

vuedraggable在vue2.0和vue3.0 中的应用

文章目录 vuedraggable在vue2.0中的应用在vue3.0中的应用 vuedraggable Vue.Draggable是一款基于Sortable.js实现的vue拖拽插件。支持移动设备、拖拽和选择文本、智能滚动,可以在不同列表间拖拽、不依赖jQuery为基础、vue 2过渡动画兼容、支持撤销操作,…

部署远程控制台访问服务Rttys,第一部分客户端(安装CMAKE)

背景:现公司有一需求,需要开发一个程序,实现页面点击按钮后跳转,远程连接到指定的虚拟机,并可以进行linux命令操作,在网上找了很多文章,发现都没有详细的步骤和部署问题处理,所以自己…

Web渗透信息收集进阶

网站敏感目录与文件 网站敏感目录表示网站目录中容易被恶意人员利用的一些目录。通常恶意人员都是通过工具扫描,来扫出网站的敏感目录,敏感目录是能够得到其他网页的信息,从而找到后台管理页面,尝试进入后台等,扫描网…

33、matlab矩阵分解汇总:LU矩阵分解、Cholesky分解、QR分解和SVD分解

1、矩阵分解简介 矩阵分解是指将一个矩阵分解成子矩阵或其他形式的矩阵表示的过程。常见的矩阵分解方法包括LU分解、QR分解、奇异值分解(SVD)、特征值分解等。 LU分解:将一个矩阵分解为一个下三角矩阵L和一个上三角矩阵U的乘积,…

淘宝评论电商API接口,揭示用户真实评价

随着互联网的快速发展,电子商务已经成为了人们生活中不可或缺的一部分。淘宝作为中国最大的在线购物平台,拥有数以亿计的消费者和商家。而用户评价作为消费者了解商品和服务的重要途径,对于商家的信誉和销售有着至关重要的影响。因此&#xf…

PMP证书有何用?

PMP证书有何用? PMP项目管理专业人士资格认证证书对从事或希望从事项目管理工作的人员有重要意义,具体体现在以下几个方面: 1. 提供职业机会: PMP是项目管理领域的国际认可标准,拥有该证书的人在求职时具备了更强的…

【node】同步获取盘符名

功能 获取电脑所有磁盘的盘符名字,并返回数组 代码 var showLetter2 function () {//返回所有盘符,同步var arr;var { execSync } require(node:child_process);//获取模块var str execSync(wmic logicaldisk get caption).toString();//将返回的变…

goframe目录文件解析

goframe 目录分块 ├─api ├─hack ├─internal │ ├─cmd │ ├─consts │ ├─controller │ ├─dao │ ├─logic │ ├─model │ │ ├─do │ │ └─entity │ ├─packed │ └─service ├─manifest │ ├─config │ ├─deploy │ │ └─kustomize │ │ ├…

LabVIEW伺服电机可应用在哪些领域

LabVIEW与伺服电机的结合,得益于LabVIEW强大的图形编程能力和伺服电机的高精度、高响应速度,广泛应用于多个领域。以下是一些主要应用领域: 1. 工业自动化 数控机床控制 LabVIEW用于控制伺服电机在数控机床中的运动,实现高精度的…