简单聊一聊零拷贝

文章目录

  • 前言
  • Direct Memory Access(DMA)
  • 传统数据io
  • mmap映射
  • sendFile
  • mmap和sendFile比较

前言

零拷贝我们经常听说,相比于传统的io在性能上有了很大提升,那么在os里面他是怎么设计的呢,与传统io又有什么区别呢

Direct Memory Access(DMA)

在聊零拷贝之前,先看一看DMA在百度百科中的解释如下

DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

通俗来讲一些硬件子系统在读取内存的时候需要通过cpu调度内存,然后再获取到内存当中的数据,这样的一个过程大大依赖cpu性能,当cpu负载过高时硬件获取内存内容的速度就会大大减小

简单聊一聊零拷贝_第1张图片

而DMA技术则不再依赖cpu,而是硬件系统直接去内存读取

简单聊一聊零拷贝_第2张图片

传统数据io

传统io模式就是我们在以前学习编程基础时的io和网络这块,在传统模式下,我们从磁盘读取一个文件然后发送至网络中,通常流程就是读取文件,然后将文件转为字节流写入Socket中,进行传输,这样一个过程在OS中中的流程如下

简单聊一聊零拷贝_第3张图片

在传统io模型中,读取一个文件的流程如下:

  • 从硬盘通过DMA拷贝将文件读取到内核缓冲区(第一次拷贝)
  • 从内存缓冲区复制到用户缓冲区中(第二次复制,且从内核态转换到用户态)
  • 从用户缓冲区复制到Socket缓冲区(第三次复制,且从用户态切换到内核态)
  • 从Socket缓冲区通过DMA拷贝到网络中(第四次复制)

从这个流程中可以看出在一次文件读取到网络的过程中,一共发生了四次复制过程,其中DMA拷贝两次CPU拷贝两次,这样的拷贝方式非常占用资源,而且存在一些不必要的复制过程

mmap映射

mmap通过与用户缓冲区共享内核缓冲区从而减少复制次数

简单聊一聊零拷贝_第4张图片

mmap读取一个文件流程如下:

  • 首先从硬盘文件复制到内核缓冲区(第一次复制)
  • 由于用户缓冲区与共内核缓冲区共享,所以不需要再将内核缓冲区复制到用户缓冲区,用户缓冲区直接操作共享的内核缓冲区即可
  • 内核缓冲区将数据拷贝到Socket缓冲区(第二次复制)
  • Socket缓冲区再使用DMA拷贝到网络中(第三次复制)

可以看到相比于传统拷贝,mmap拷贝的复制次数减少了一次。由于用户态中的用户缓冲区直接操作内核缓冲区,因此用户态对文件的操作有容易丢失的缺点。

sendFile

在mmap中依然发生了三次复制,能不能再进行优化呢?Linux2.1提供了sendFile函数来进行文件拷贝传输,其基本流程如下
简单聊一聊零拷贝_第5张图片

  • 首先从硬盘文件复制到内核缓冲区(第一次复制)
  • 从内核态再将文件拷贝到Socket缓冲区(第二次复制)
  • 从Socket缓冲区使用DMA拷贝到网络(第三次复制)

从这个流程可以看出sendFile的拷贝过程依然是三次复制,但是用户缓冲区没有参与到拷贝当中,因此在这个过程中虽然复制次数没变,但是减少了用户态和内核态的切换次数,效率有了一定提升

Linux2.4之后在这个基础上又进行了修改,修改后的拷贝流程如下

简单聊一聊零拷贝_第6张图片

  • 首先从硬盘文件复制到内核缓冲区(第一次复制)
  • 从内核缓冲区直接拷贝到网络当中(第二次复制)
  • 内核缓冲区拷贝一些offset和length信息到Socket缓冲区

从上面的流程可以看到整个过程发生了三次拷贝,但是由于从内核缓冲区复制到Socket缓冲区拷贝内容较少,其消耗可忽略不计,因此修改后的SendFile可以看成之发生了两次拷贝,与传统拷贝相比拷贝次数减少一半,并且用户态和内核态的切换更少,性能更高

mmap和sendFile比较

虽然叫零拷贝,但并不意味着没有发生复制过程,而是相比于传统拷贝复制过程更少,用户态和内核态切换次数更少

mmap和sendFile比较如下

mmap sendFile
mmap适合小文件的拷贝 sendFile适合大文件的传输
mmap发生4次用户态和内核态切换 sendFile发生3次用户态和内核态切换
mmap发生3次数据拷贝 sendFile发生2次数据拷贝

你可能感兴趣的:(Linux,#,Kafka,linux,操作系统,kafka)