内功修炼-操作系统之文件管理和IO基础
文件系统基础
磁盘组织与管理
基础IO
在计算机操作系统中,所谓的I/O就是 输入(Input)
和输出(Output)
,也可以理解为读(Read)和写(Write),针对不同的对象,I/O模式可以划分为磁盘IO模型和网络IO模型。
IO操作会涉及到用户空间和内核空间的转换,先来理解以下规则:
- 内存空间分为
用户空间
和内核空间
,也称为用户缓冲区和内核缓冲区; - 用户的应用程序不能直接操作内核空间,需要将数据从内核空间拷贝到用户空间才能使用;
- 无论是read操作,还是write操作,都只能在内核空间里执行;
- 磁盘IO和网络IO请求加载到内存的数据都是先放在内核空间的;
用户空间&内核空间
简单说,内核空间
是操作系统内核代码运行的地方
,用户空间
是用户程序代码运行的地方
。当应用进程执行系统调用陷入内核代码中执行时就处于内核态
,当应用进程在运行用户代码时就处于用户态
。
// 简单看几行代码,分析下是应用程序在用户空间和内核空间之间的切换过程:
str = "i am qige" // 用户空间
x = x + 2
file.write(str) // 切换到内核空间
y = x + 4 // 切换回用户空间
查看 CPU 时间在 User Space 与 Kernel Space 之间的分配情况,可以使用top命令。在第三行中,%Cpu(s): 5.7us(用户空间), 9.2sy(内核空间), 0.0ni, 96.6id(闲置)
。
PIO&DMA工作原理
大家都知道一般我们的数据是存储在磁盘上的,应用程序想要读写这些数据肯定就需要加载到内存中。接下来给大家介绍下 PIO
和 DMA
这两种 IO 设备和内存之间的数据传输方式。
PIO缺点:每次IO请求都需要CPU多次参与,效率很低。
DMA(直接内存访问,Direct Memory Access)跟PIO模式相比,DMA就是CPU的一个代理,它负责了一部分的拷贝工作,从而减轻了CPU的负担
。需要注意的是,DMA承担的工作是从磁盘的缓冲区
到内核缓冲区
或网卡设备
到内核的soket buffer
的拷贝工作,以及内核缓冲区
到磁盘缓冲区
或内核的 soket buffer
到网卡设备
的拷贝工作,而内核缓冲区到用户缓冲区之间的拷贝工作仍然由CPU负责。
缓冲IO和直接IO
用户空间是不能直接访问内核空间的数据的,如果需要访问怎么办?很简单,就需要将数据从内核空间拷贝的用户空间。
缓冲IO
:其实就是磁盘中的数据通过 DMA 先拷贝到内核空间,然后再从内核空间拷贝到用户空间。大多数采用此方法。直接IO
:磁盘中的数据直接通过 DMA 拷贝到用户空间。通常由数据库、消息中间件等需要应用程序自己实现数据缓存的管理。
缓冲IO的优缺点
- 在一定程度上分离了内核空间和用户空间,保护系统本身的运行安全;
- 因为内核中有缓冲,可以减少读盘的次数,从而提高性能。
- 数据在传输过程中需要在应用程序地址空间(用户空间)和内核缓冲(内核空间)之间进行多次数据拷贝操作
直接IO的优缺点
- 最直观目的是减少一次从内核缓冲区到用户程序缓冲的数据复制
- 如果访问的数据不在应用程序缓冲中,那么每次数据都会直接从磁盘进行加载,这种直接加载会非常缓慢。通常 直接I/O 跟 异步I/O 结合使用会得到较好的性能。
DMA与零拷贝技术
磁盘
可以说是计算机系统中最慢的硬件之一,读写速度比内存慢10倍以上,所以针对优化磁盘的技术非常的多,比如:零拷贝,直接I/O,异步I/O等等。
这里我们就以文件传输为切入点,分析I/O工作方式,以及如何优化文件传输的性能。
DMA技术
,全称为Direct Memory Access(又称直接内存访问技术
)。
没有DMA技术前的I/O过程
- 首先在用户进程进行read()系统调用的时候,操作系统会由用户态切换到内核态,然后由CPU向磁盘发起IO请求。
- 磁盘在接收到IO请求以后,进行数据准备工作,将数据放在磁盘控制器缓冲区里。
- 在数据准备工作完成以后,磁盘向CPU发出IO中断信号。
- CPU收到中断信号后,会先将磁盘缓冲区中的文件copy到PageCache中,再将数据从PageCache中copy到用户缓冲区中。在这期间CPU是无法执行其他任务的。copy完成之后read()调用返回,操作系统刚从内核态切换回用户态。
故可以得知:在数据传输的过程,需要CPU亲自的去拷贝数据,并且在这期间CPU无法去做其他事情。简单的搬运几个字符没有问题,但是当处理大量数据的时候,如果每次都让CPU来搬运,显然忙不过来。
有DMA技术之后的I/O过程
- 当有了DMA控制器以后,在进程向CPU发出read()调用以后,CPU向DMA控制器发起IO请求,然后DMA控制器再向磁盘发出IO请求。
- 当磁盘接收到IO请求以后,会进行数据准备工作,将数据放到磁盘数据缓冲区当中。
- 当磁盘的数据准备工作完成以后,不再向CPU发出中断信号,而是通知DMA控制器。
- DMA控制器在接收到通知以后,将数据从
磁盘控制器缓冲区中copy到内核缓冲区
中。在这期间并不占用CPU,CPU可以处理其他的事情,执行其他的任务。 - DMA控制器处理完之后向CPU发出中断信号,由CPU将
数据从内核缓冲区copy至用户缓冲区
中。copy完成之后read()调用返回,操作系统从内核态切换回用户态。
注意:起初的DMA控制器只在主板上,但是现在IO设备越来越多,数据传输的需求也不尽相同,所以现在每个IO设备中都有DMA控制器。
在进行read调用的时候,操作系统由用户态转为内核态,需要进行DMA拷贝
和CPU拷贝
各一次。(DMA拷贝是指由DMA控制器将磁盘控制器缓冲区中的数据拷贝到内核缓冲区中,CPU拷贝是指将数据从内核缓冲区中copy到用户缓冲区中),在read调用结束以后,操作系统再从内核态切换回用户态。
在进行write调用的时候,操作系统由用户态转为内核态,需要进行CPU拷贝和DMA拷贝各一次。(CPU拷贝是指将用户缓冲区的数据拷贝到socket缓冲区中。而DMA拷贝是指将socket缓冲区中的数据拷贝到网卡中。)
在文件传输场景下,我们无需在用户空间对数据进行再加工。因此用户缓冲区的存在是没有必要的。
如何实现零拷贝
传统 I/O 的工作方式在读写文件时,共发生了四次
数据拷贝,两次是DMA拷贝
,另外两次则是通过CPU拷贝
。要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数
。
// 传统 I/O 的工作方式是
read(file, tmp_buf, len);
write(socket, tmp_buf, len);
// mmap + write怎么实现的零拷贝?
mmap() 系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作
buf = mmap(file, len);
write(sockfd, buf, len);
// sendfile怎么实现的零拷贝?
// 在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile()
// 它可以替代前面的 read() 和 write() 这两个系统调用,这样就可以减少一次系统调用,也就减少了 2 次上下文切换的开销。
// 其次,该系统调用,可以直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态,这样就只有 2 次上下文切换,和 3 次数据拷贝。
#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
// 如果网卡支持SG—DMA,且读写网络数据时,就可以将数据拷贝次数减小为两次。
// 从 Linux 内核 2.4 版本开始起,对于支持网卡支持 SG-DMA 技术的情况下, sendfile() 系统调用的过程发生了点变化
// 可以进一步减少通过 CPU 把内核缓冲区里的数据拷贝到 socket 缓冲区的过程
这就是所谓的零拷贝(Zero-copy)技术,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的
。
零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数,只需要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,而且 2 次的数据拷贝过程,都不需要通过 CPU,2 次都是由 DMA 来搬运
。
PageCache
零拷贝的内核缓冲区正是使用了PageCache技术。在零拷贝技术中,用PageCache来缓存最近被访问过的数据,当空间不足时淘汰最久未使用的缓存。并且给予局部性原理,进行预读,减少IO次数。
但是在传输大文件的时候,性能损失非常大。因为在传输大文件的时候如果采用PageCache,PageCache容量有限,则PageCache由于长时间被大文件占据,其他热点的小文件可能就无法充分使用到。这样磁盘的读写性能就会降低。并且PageCache中的大文件数据,由于没有享受到缓存带来的好处,但却耗费 DMA 多拷贝到 PageCache 一次,造成资源的浪费。
因此PageCache 被大文件占据,而导致「热点」小文件无法利用到 PageCache,这样在高并发的环境下,会带来严重的性能问题。
大文件传输采用什么实现
核心思想在于:在发起异步IO读以后,不等待数据就位就可以立即返回,然后去处理其他任务。直到收到内核返回的读取成功通知,才去处理数据。这样就解决了高并发场景下零拷贝技术大文件读取的阻塞问题。因此,对于传输大文件,应该使用异步IO+直接IO的方法。而对于小文件,则应该使用零拷贝。
扩展阅读
操作系统之文件管理,万字长文让你彻底弄懂!!!
《操作系统》——文件管理(上)
《操作系统》——文件管理(下)
《操作系统》——输入输出管理
DMA与零拷贝技术
最后更新于 2024-01-15 02:25:22 并被添加「」标签,已有 1109 位童鞋阅读过。
本站使用「署名 4.0 国际」创作共享协议,可自由转载、引用,但需署名作者且注明文章出处
此处评论已关闭