Linux磁盘IO、网络IO、零拷贝详解

一、什么是I/O?

在计算机操作系统中,所谓的I/O就是输入(input)和输出(output),也可以理解为读(read)和写(write),针对不同的对象,I/O模式可以划分为磁盘IO模型和网络IO模型

二、IO操作本质是用户空间和内核空间的转换,规则如下:

  • 内存空间分为用户空间和内核空间,也称为用户缓冲区和内核缓冲区
  • 用户的应用程序不能直接操作内核空间,需要将数据从内核空间拷贝到用户空间才能使用
  • 无论是read操作,还是write操作,都只能在内核空间里执行
  • 磁盘IO操作、网络请求加载到内存的数据一开始都是先放到内核缓冲区的

三、IO调用步骤之读(read)操作和写(write)

注:绿色的图型表示数据存储的位置,绿色的箭头则表示数据的复制

图1解析:

1、从左到右:Linux IO包含两部分,磁盘IO(Disk I/O)和网络IO(Network I/O)

2、从上到下:存储又被划分为三部分:用户空间(User space)、内核空间(Kerner space)及物理设备(Physical devices)

从上到下,为什么划分为三层?

Linux操作系统为了安全考虑,其内核管理了几乎所有的硬件设备,不允许用户进程直接访问。因此,逻辑上计算机被分为用户空间和内核空间(外设及其驱动是被划分在内核空间的)

运行在用户空间的进程就是用户态,运行在内核空间的进程就是内核态。用户态的进程,访问不了内核空间的数据,所以就需要由内核态的进程把数据拷贝到用户态。

3、缓存I/O(Buffered I/O)

3.1、磁盘IO(Disk I/O):

读操作:当应用程序调用read()方法时,操作系统检查内核缓冲区是否存在需要的数据,如果存在,那么就直接把内核空间的数据copy到用户空间,供用户的应用程序使用;如果内核缓冲区没有需要的数据,则通过DMA方式从磁盘中读取数据到内核缓冲区(DMA Copy),然后把内核空间的数据copy到用户空间(Cpu Copy)(上图绿色实线部分)

写操作:当应用程序调用write()方法时,应用程序将数据从用户空间copy到内核空间的缓冲区(如果用户空间没有相应的数据,则需要从磁盘-->内核缓冲区-->用户缓冲区依次读取),这时对用户程序来说写操作就已经完成,至于什么时候把数据再写到磁盘,由操作系统决定。操作系统将要写入磁盘的数据先保存于系统为写缓存分配的内存空间中,当保存到内存池中的数据达到一个程度时,便将数据保存在硬盘中。这样可以减少实际的磁盘操作,有效的保护磁盘免于重复的读写操作而导致的损坏,也能减少写入所需的时间。除非应用程序显式的调用了sync命令,立即把数据写入磁盘。如果应用程序没准备好写的数据,则必须先从磁盘读取数据才能执行写操作,这时会涉及到四次缓冲区的copy:

a、第一次从磁盘的缓冲区读取数据到内核缓冲区(DMA Copy);

b、第二次从内核缓冲区复制到用户缓冲区(Cpu Copy);

c、第三次从用户缓冲区写到内核缓冲区(Cpu Copy);

d、第四次从内核缓冲区写到磁盘(DMA Copy);(上图绿色实线部分双向箭头)

磁盘IO延时:

  • 寻道时间:把磁头移动到指定磁道上所经历的时间
  • 旋转延时间:指定扇区移动到磁头下面所经历的时间
  • 传输时间:数据的传输时间(数据读出或写入的时间)

Page cache 和Buffer cache:

Page cache也叫页缓冲或文件缓冲。是由好几个磁盘块构成,大小通常是4K,在64位系统上为8K。构成的几个磁盘块在物理磁盘上不一定连续,文件的组织单位为一页,也就是一个Page cache大小。Page cache是建立在文件系统(Ex4)之上的,因此其缓存的是逻辑数据。Buffer cache是建立在块层之上的,因此其缓存的是物理辑数据。Linux大约在2.4.10之后,Page cache与Buffer cache合并了

(所以图中Buffer cache是灰色的,为了更容易理解IO原理,黄色和灰色部分都可以不考虑了)

DMA(直接内存访问)方式:

DMA是一种与CPU共享内存总线的设备,它可以代替CPU,把数据从内存到设备之间进行拷贝。仅在传送一个或多个数据块的开始和结束时,才需CPU干预(发送DMA中断),整块数据的传送是在DMA的控制器的控制下完成的。

3.2、网络I/O(Network I/O)

读操作:网络IO即可以从物理磁盘中读数据,也可以从socket中读数据(从网卡中获取)。当从物理磁盘中读数据的时候,其流程和磁盘IO的读操作一样。当从socket中读数据,应用程序需要等待客户端发送数据,如果客户端还没有发送数据,对应的应用程序将会被阻塞,直接客户端发送了数据,该应用程序才会被唤醒,从Socket协议栈(即网卡)中读取客户端发送的数据到内核空间(DMA copy),然后把内核空间的数据copy到用户空间

写操作:为了简化描述,我们假设网络IO的数据从磁盘中获取,读写操作流程如下:

  • 当应用程序调用read()方法时,通过DMA方式将数据从磁盘拷贝到内核缓冲区(DMA copy);
  • 由cpu控制,将内核缓冲区的数据拷贝到用户空间的缓冲区中,供应用程序使用(CPU copy);
  • 当应用程序调用write()方法时,cpu会把用户缓冲区的数据copy到内核缓冲区的Socket Buffer中(CPU copy);
  • 最后通过DMA方式将内核空间中的Socket Buffer拷贝到Socket协议栈(即网卡设备)中传输(DMA copy);

网络IO的延时:网络IO主要延时是由服务器响应延时 + 带宽限制 + 网络延时 + 跳转路由延时 + 本地接收延时 决定。一般为几十到几千毫秒,受环境影响较大。所以一般来说,网络IO延时要大于磁盘IO延时

缓存I/O的一致性和安全性:如果出现进程死,内核死,掉电这样事件发生。数据会丢失吗?

  • 进程死:如果数据还处在application cache或clib cache的时候,数据会丢失;
  • 内核死:即使进入了page cache(完成了write),如果没有进行sync操作,数据还是会丢失;
  • 掉电:进行了sync,数据就一定写入了磁盘了吗?答案是:不一定;
  • 注意到图1中,磁盘旁边的绿色图型了吗?它表示的是磁盘上的缓存。写数据达到一个程度时才真正写入磁盘

缓存I/O的缺点:在缓存I/O机制中,DMA方式可以将数据直接从磁盘读到页缓存中,或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输。这样的话,数据 在传输过程中需要在应用程序地址空间和页缓存之间进行多次数据拷贝操作,这些数据拷贝操作所带来的CPU以及内存开销是非常大的。对于某些特殊的应用程序来说,避开操作系统内核缓冲区,而直接在应用程序地址空间和磁盘之间传输数据,会比使用操作系统内核缓冲区获取更好的性能,因此引入"Direct I/O"。

4、直接I/O(Direct I/O)

凡是通过直接 I/O 方式进行数据传输,数据均直接在用户地址空间的缓冲区和磁盘之间直接进行传输,完全不需要页缓存的支持。

进程在打开文件的时候设置对文件的访问模式为 O_DIRECT ,这样就等于告诉操作系统进程在接下来使用 read() 或者 write() 系统调用去读写文件的时候使用的是直接 I/O 方式,所传输的数据均不经过操作系统内核缓存空间。

直接I/O优点:减少操作系统缓冲区和用户地址空间的拷贝次数。降低CPU开销和内存带宽 。对于某些应用程序来说简单是福音,将会大大提高性能。

直接I/O缺点:直接 I/O 并不总能让人如意。直接 I/O 的开销也很大,应用程序没有控制好读写,将会导致磁盘读写的效率低下。磁盘的读写是通过磁头的切换到不同的磁道上读取和写入数据,如果需要写入数据在磁盘位置相隔比较远,就会导致寻道的时间大大增加,写入读取的效率大大降低。

Direct I/O 本质是 DMA 设备把数据从用户空间拷贝到设备,或是从设备拷贝到用户空间。

5、mmap

mmap 本质是内存共享机制,它把 page cache 地址空间映射到用户空间,换句话说,mmap 是一种特殊的 Buffered I/O

offset 是文件中映射的起始位置,length 是映射的长度。

mmap内存映射原理:

mmap 内存映射过程:

    • 进程在虚拟地址空间中为映射创建虚拟映射区域。
    • 内核把文件物理地址和进程虚拟地址进行映射。
    • 进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝。
    • 换句话说,在调用 mmap 后,只是在进程的虚拟空间中分配了一段空间,真实的物理地址还不会分配的。
    • 当进程第一次访问这段空间(当作内存一样),CPU 陷入 OS 内核执行异常处理。然后异常处理会在这个时间分配物理内存,并用文件的内容填充这片内存,然后才返回进程的上下文,这时进程才会感知到这片内存里有数据。

mmap本质:

mmap 本质是内存共享机制,它把 page cache 地址空间映射到用户空间,换句话说,mmap 是一种特殊的 Buffered I/O。

因为底层有 CPU 的 MMU 支持,自然会转换到物理区域,对于进程而言是无感知。所以,磁盘数据加载到 page cache 后,用户进 程可以通过指针操作直接读写 page cache,不再需要系统调用和内存拷贝。

因此,offset 必须是按 page size 对齐的(不对齐的话就会映射失败)。

mmap 映射区域大小必须是物理页大小(page size)的整倍数(32 位系统中通常是 4k)。length 对齐是靠内核来保证的,比如文件长度是 10KB,你映射了 5KB,那么内核会将其扩充到 8KB。

6、Linux五大网络IO模型

1.BIO:阻塞模式IO

举个例子:
一个人去 商店买一把菜刀,
他到商店问老板有没有菜刀(发起系统调用)
如果有(表示在内核缓冲区有需要的数据)
老板直接把菜刀给买家(从内核缓冲区拷贝到用户缓冲区)
这个过程买家一直在等待如果没有,商店老板会向工厂下订单(IO操作,等待数据准备好)
工厂把菜刀运给老板(进入到内核缓冲区)
老板把菜刀给买家(从内核缓冲区拷贝到用户缓冲区)
这个过程买家一直在等待
是同步io

2.NIO:非阻塞模式IO

用户进程发起请求,如果数据没有准备好,那么立刻告知用户进程未准备好;此时用户进程可选择继续发起请求、或者先去做其他事情,稍后再回来继续发请求,直到被告知数据准备完毕,可以开始接收为止; 数据会由用户进程完成拷贝

举个例子:

一个人去 商店买一把菜刀,

他到商店问老板有没有菜刀(发起系统调用)

老板说没有,在向工厂进货(返回状态)

买家去别地方玩了会,又回来问,菜刀到了么(发起系统调用)

老板说还没有(返回状态)

买家又去玩了会(不断轮询)

最后一次再问,菜刀有了(数据准备好了)

老板把菜刀递给买家(从内核缓冲区拷贝到用户缓冲区)

整个过程轮询+等待:轮询时没有等待,可以做其他事,从内核缓冲区拷贝到用户缓冲区需要等待

是同步io

3.I/O多路复用模型

类似BIO,只不过找了一个代理,来挂起等待,并能同时监听多个请求; 数据会由用户进程完成拷贝

举个例子:多个人去 一个商店买菜刀,

多个人给老板打电话,说我要买菜刀(发起系统调用)

老板把每个人都记录下来(放到select中)

老板去工厂进货(IO操作)

有货了,再挨个通知买到的人,来取刀(通知/返回可读条件)

买家来到商店等待,老板把到给买家(从内核缓冲区拷贝到用户缓冲区)

多路复用:老板可以同时接受很多请求(select模型最大1024个,epoll模型),

但是老板把到给买家这个过程,还需要等待,

是同步io

select本质也是轮询最多可以监听1024个,而epoll模型是事件驱动,好了会主动告诉你

-select:小明,你写好了么?小红你写好了么?.......

-epoll:同学写好了,举手告诉老师来检查(nginx、tornado用的是epoll)windows平台不支持epoll,用的是select

4.信号驱动IO

事先发出一个请求,当有数据后会返回一个标识回调,这时你可以去请求数据(不是轮询请求,而是收到返回标识后请求)。好比银行排号,当叫到你的时候,你就可以去处理业务了(复制数据时阻塞)。

信号驱动IO,调用sigaltion系统调用,当内核中IO数据就绪时以SIGIO信号通知请求进程,请求进程再把数据从内核读入到用户空间,这一步是阻塞的

5.异步IO--AIO

发起请求立刻得到回复,不用挂起等待; 数据会由内核进程主动完成拷贝,目前不成熟

举个例子:还是买菜刀
现在是网上下单到商店(系统调用)
商店确认(返回)
商店去进货(io操作)
商店收到货把货发个卖家(从内核缓冲区拷贝到用户缓冲区)
买家收到货(指定信号)整个过程无等待
异步io

总结:

  • 同步I/O与异步I/O判断依据是,是否会导致用户进程阻塞
  • BIO中socket直接阻塞等待(用户进程主动等待,并在拷贝时也等待)
  • NIO中将数据从内核空间拷贝到用户空间时阻塞(用户进程主动询问,并在拷贝时等待)
  • IO Multiplexing中select等函数为阻塞、拷贝数据时也阻塞(用户进程主动等待,并在拷贝时也等待)
  • AIO中从始至终用户进程都没有阻塞(用户进程是被动的)

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

(✌)粤嵌—2024/5/7—除自身以外数组的乘积

代码实现&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* productExceptSelf(int *nums, int numsSize, int *returnSize) {// 左乘积int l[numsSize];l[0] 1;for (int i 1; i < numsSize; i) {l[i] l[i - 1] * nums[…

git commit 提交报错pre-commit hook failed (add --no-verify to bypass) 解决方法,亲测有效

问题截图 今天在执行 git commit 命令时报错&#xff1a;pre-commit hook failed (add --no-verify to bypass) 解决 参考文章&#xff1a;git commit报错&#xff1a;pre-commit hook failed的解决方法 具体原理什么的就不解释了&#xff0c;可以看看上面的参考文章 解决方…

Spring 当中的Bean 作用域

Spring 当中的Bean 作用域 文章目录 Spring 当中的Bean 作用域每博一文案1. Spring6 当中的 Bean的作用域1.2 singleton 默认1.3 prototype1.4 Spring 中的 bean 标签当中scope 属性其他的值说明1.5 自定义作用域&#xff0c;一个线程一个 Bean 2. 总结:3. 最后&#xff1a; 每…

【计算机网络】计算机网络的性能指标

计算机网络的性能指标被用来从不同方面度量计算机网络的性能。常用的八个计算机网络性能指标&#xff1a;速率、带宽、吞吐量、时延、时延带宽积、往返时间、利用率、丢包率。 一.速率 (1) 数据量 比特&#xff08;bit&#xff0c;记为小写b&#xff09;是计算机中数据量的基…

JavaScript逆向技术

JavaScript逆向之旅&#xff1a;深入解析与实践 在数字时代&#xff0c;前端技术的迅速发展使得Web应用变得更加丰富和复杂。JavaScript&#xff0c;作为前端的核心语言&#xff0c;其安全性和隐私保护问题也逐渐浮出水面。JavaScript逆向&#xff0c;作为一种从前端代码中提取…

抖音小店个人店和个体店有什么不同?区别问题,新手必须了解!

哈喽~我是电商月月 新手开抖音小店入驻时会发现&#xff0c;选择入驻形式时有三个选择&#xff0c;个人店&#xff0c;个体店和企业店 其中&#xff0c;个人店和个体店只差了一个字&#xff0c;但个人店不需要营业执照&#xff0c;是不是入驻时选择个人店会更好一点呢&#x…

图像处理之PCA(C++)

图像处理之PCA&#xff08;C&#xff09; 文章目录 图像处理之PCA&#xff08;C&#xff09;前言一、PCA原理1.原理思想2.实现步骤 二、代码实现总结 前言 在科研、工程应用中&#xff0c;我们往往所获取的数据都包含着很多冗余的信息&#xff0c;这些冗余的信息会对我们分析数…

卷价格不如卷工艺降本增效狠抓模块规范化设计

俗话说&#xff0c;“卷价格不如卷工艺”&#xff0c;这意味着在追求成本控制和效率提升的过程中&#xff0c;蓝鹏的领导认为蓝鹏应该更注重工艺的优化和创新&#xff0c;而不仅仅是价格的竞争。而模块规范化设计正是实现这一目标的有效途径。 模块规范化设计可以提高生产效率…

【超好用的前端表单辅助功能】

前端表单辅助功能 1. 根据模块自动生成目录锚点定位2. 描点定位动态组件3. 隔离组件&#xff0c;组件内部实现校验逻辑&#xff0c;交给提交按钮统一处理4. 选择不同的类型需要重组不同的模块展示&#xff0c;并整合数据传给后端 最近做了一个复杂的表单&#xff0c;涉及到的技…

深入Django:用户认证与权限控制实战指南

title: 深入Django&#xff1a;用户认证与权限控制实战指南 date: 2024/5/7 18:50:33 updated: 2024/5/7 18:50:33 categories: 后端开发 tags: AuthDecoratorsPermissionsGuardianRESTAuthSessionMgmtMFA 第1章&#xff1a;入门Django与设置 1.1 Django安装与环境配置 在…

3399 ubuntu系统启动后,gpio已被初始化问题查找

问题描述: 使用cat /sys/kernel/debug/gpio后发现,gpio-55已经被设备树初始化了。 如果要找到这个引脚的设置代码,需要一点点查找。这里记录了比较快速的办法 gpio引脚变换 gpio-55需要转换成对应的引脚编号 根据https://blog.csdn.net/ch122633/article/details/120233…

超详细——集成学习——Adaboost实现多分类——附代码

资料参考 1.【集成学习】boosting与bagging_哔哩哔哩_bilibili 集成学习——boosting与bagging 强学习器&#xff1a;效果好&#xff0c;模型复杂 弱学习器&#xff1a;效果不是很好&#xff0c;模型简单 优点 集成学习通过将多个学习器进行结合&#xff0c;常可获得比单一…

4.请求体

什么是请求体(Request Body) 请求体是客户端发送到API的数据。 响应体是API发送给客户端的数据 API几乎总是必须发送一个响应体&#xff0c;但是客户端并不需要一直发送请求体 定义请求体&#xff0c;需要使用 Pydantic 模型 不能通过GET请求发送请求体发送请求体数据&…

Android版本依赖Version catalog

曾经我们使用config.gradle文件进行版本依赖配置&#xff0c;然后在project的build.gradle.kts中使用如下方式引入&#xff1a; apply(from "./config.gradle") 缺点&#xff1a;在project的module中引用无任何提示&#xff0c;无法跳转到指定引用 一、创建versio…

局域网监控软件能干什么|有哪些好用的局域网监控软件

企业局域网已成为日常工作中不可或缺的一部分。 然而&#xff0c;网络环境的复杂性和员工上网行为的多样性&#xff0c;使得企业面临着诸多安全风险和管理挑战。 因此&#xff0c;高效局域网监控上网记录监测成为了企业保障信息安全和提升工作效率的重要手段。 高效局域网监控…

Java 框架安全:Struts2 漏洞序列测试.

什么是 Struts2 框架 Struts 2 是一个用于创建企业级 Java 应用程序的开源框架。它是一个 MVC&#xff08;模型-视图-控制器&#xff09;框架&#xff0c;用于开发基于 Java EE&#xff08;Java Platform, Enterprise Edition&#xff09;的 Web 应用程序。Struts 2 主要解决…

STM32控制DS1302时钟模块获取实时时间

欢迎入群共同学习交流 时间记录&#xff1a;2024/4/30 一、知识点 &#xff08;1&#xff09;读写数据时序&#xff08;伪SPI协议&#xff09; 1.1 读写时序默认电平均为SCLK线低电平&#xff0c;CE线低电平 1.2 写数据&#xff0c;CE线拉高为高电平&#xff0c;开始传输数据…

CANoe测试报告格式转换

CANoe测试报告使用工具Vector CANoe Test Report Viewer进行格式转换 一、 Test Report Viewer format转换为PDF格式 使用工具Vector CANoe Test Report Viewer打开*.vtestreport文件,点击File | Export | Export PDF,可以将测试报告转为PDF格式。 二、Test Report Viewe…

想做视频号小店,为何不建议开通个体店?开店步骤+做店思路如下

我是王路飞。 如果你想在视频号开通店铺的话&#xff0c;那么一定不要使用个体执照开通个体店&#xff1f; 这是为什么呢&#xff1f; 原因很简单&#xff0c;视频号个体店是无法入驻优选联盟的&#xff0c;只能企业店可以入驻。 因为现阶段视频号小店的自然流量很少&#…

18、ESP32 ESP-NOW 点对点通信

ESP-NOW 是乐鑫自主研发的无连接通信协议&#xff0c;具有短数据包传输功能。该协议使多个设备能够以简单的方式相互通信。 ESP-NOW 功能 ESP-NOW 支持以下功能&#xff1a; 加密和未加密的单播通信;混合加密和未加密的对等设备;最多可携带 250 字节 的有效载荷;发送回调功能…