理解零拷贝原理

版权声明:本文为博主原创文章,转载时请注明! https://blog.csdn.net/u013018618/article/details/80146617
  • 引言
传统的 Linux 操作系统的标准 I/O 接口是基于数据拷贝操作的,即 I/O 操作会导致数据在操作系统内核地址空间的缓冲区和应用程序地址空间定义的缓冲区之间进行传输。这样做最大的好处是可以减少磁盘 I/O 的操作,因为如果所请求的数据已经存放在操作系统的高速缓冲存储器中,那么就不需要再进行实际的物理磁盘 I/O 操作。但是数据传输过程中的数据拷贝操作却导致了极大的 CPU 开销,限制了操作系统有效进行数据传输操作的能力。
零拷贝( zero-copy )技术可以有效地改善数据传输的性能,在内核驱动程序(比如网络堆栈或者磁盘存储驱动程序)处理 I/O 数据的时候,零拷贝技术可以在某种程度上减少甚至完全避免不必要 CPU 数据拷贝操作。

  • 什么是零拷贝?
零拷贝就是一种避免 CPU 将数据从一块存储拷贝到另外一块存储的技术。针对操作系统中的设备驱动程序、文件系统以及网络协议堆栈而出现的各种零拷贝技术极大地提升了特定应用程序的性能,并且使得这些应用程序可以更加有效地利用系统资源。这种性能的提升就是通过在数据拷贝进行的同时,允许 CPU 执行其他的任务来实现的。
零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,从而有效地提高数据传输效率。而且,零拷贝技术减少了用户应用程序地址空间和操作系统内核地址空间之间因为上下文切换而带来的开销。进行大量的数据拷贝操作其实是一件简单的任务,从操作系统的角度来说,如果 CPU 一直被占用着去执行这项简单的任务,那么这将会是很浪费资源的;如果有其他比较简单的系统部件可以代劳这件事情,从而使得 CPU 解脱出来可以做别的事情,那么系统资源的利用则会更加有效。综上所述,零拷贝技术的目标可以概括如下:
避免数据拷贝
①避免操作系统内核缓冲区之间进行数据拷贝操作。
②避免操作系统内核和用户应用程序地址空间这两者之间进行数据拷贝操作。
③用户应用程序可以避开操作系统直接访问硬件存储。
④数据传输尽量让 DMA 来做。
将多种操作结合在一起
①避免不必要的系统调用和上下文切换。
②需要拷贝的数据可以先被缓存起来。
③对数据进行处理尽量让硬件来做。

  • 零拷贝原理
1.io读写的方式
1.1中断
1.2DMA
2.中断方式
2.1中断方式的流程图如下:

①用户进程发起数据读取请求
②系统调度为该进程分配cpu
③cpu向io控制器(ide,scsi)发送io请求
④用户进程等待io完成,让出cpu
⑤系统调度cpu执行其他任务
⑥数据写入至io控制器的缓冲寄存器
⑦缓冲寄存器满了向cpu发出中断信号
⑧cpu读取数据至内存
2.2缺点:中断次数取决于缓冲寄存器的大小
3.DMA : 直接内存存取
3.1DMA方式的流程图如下:

①用户进程发起数据读取请求
②系统调度为该进程分配cpu
③cpu向DMA发送io请求
④用户进程等待io完成,让出cpu
⑤系统调度cpu执行其他任务
⑥数据写入至io控制器的缓冲寄存器
⑦DMA不断获取缓冲寄存器中的数据(需要cpu时钟)
⑧传输至内存(需要cpu时钟)
⑨所需的全部数据获取完毕后向cpu发出中断信号
3.2优点:减少cpu中断次数,不用cpu拷贝数据
4.数据拷贝
4.1下面展示了 传统方式读取数据后并通过网络发送 所发生的数据拷贝:

①一个read系统调用后,DMA执行了一次数据拷贝,从磁盘到内核空间
②read结束后,发生第二次数据拷贝,由cpu将数据从内核空间拷贝至用户空间
③send系统调用,cpu发生第三次数据拷贝,由cpu将数据从用户空间拷贝至内核空间(socket缓冲区)
④send系统调用结束后,DMA执行第四次数据拷贝,将数据从内核拷贝至协议引擎
⑤另外,这四个过程中,每个过程都发生一次上下文切换
4.2内存缓冲数据,主要是为了提高性能,内核可以预读部分数据,当所需数据小于内存缓冲区大小时,将极大的提高性能。
4.3零拷贝是为了消除这个过程中冗余的拷贝
5.零拷贝-sendfile 对应到java中
FileChannel.transferTo(long position, long count, WritableByteChannel target)//将数据从文件通道传输到了给定的可写字节通道
5.1避免了第2,3步的数据拷贝,参考下图:

①DMA从拷贝至内核缓冲区
②cpu将数据从内核缓冲区拷贝至内核空间(socket缓冲区)
③DMA将数据从内核拷贝至协议引擎
④这三个过程中共发生2次上下文切换,分别为发起读取文件和发送数据
5.2以上过程发生了三次数据拷贝,其中有一次为cpu完成
5.3linux内核2.4以后,socket缓冲区做了调整,DMA带收集功能,如下图:

①DMA从拷贝至内核缓冲区
②将数据的位置和长度的信息的描述符增加至内核空间(socket缓冲区)
③DMA将数据从内核拷贝至协议引擎
6.零拷贝-mmap 对应到java中
MappedByteBuffer//文件内存映射
6.1数据不会复制到用户空间,只在内核空间,与sendfile类似,但是应用程序可以直接操作该内存。

猜你喜欢

转载自blog.csdn.net/u013018618/article/details/80146617
今日推荐