什么是零拷贝

摘要:
当程序请求网络数据时,需要经过两个副本:①: 程序需要等待数据从网卡复制到内核空间;②: 由于用户程序无法访问内核空间,内核必须将数据复制到用户空间,以便用户空间中的程序可以访问数据;2.什么是零拷贝和零拷贝技术是指当计算机执行操作时,CPU不需要先将数据从一个存储器复制到另一个特定区域。

 1、名词介绍

  内核:操作系统的核心

  用户空间:指的是用户进程的运行空间

  内核空间:指的是内核的运行空间

  用户态:如果进程运行在用户空间就是用户态

  内核态:如果进程运行在内核空间就是内核态

  DMA拷贝:

    对一个IO操作而言,是通过CPU发出对应的指令来完成的,但是相比CPU来说,IO的速度太慢了,CPU有大量的时间处于等待IO状态。

    因此就产生了DMA(Direct Memory Access):直接内存访问技术。是一种无需CPU的参与就可以让IO设备与系统内存之间进行双向数据传输机制。

    使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。DMA方式的数据传输由DMA控制器(DMAC)控制,在传输期间,CPU可以并发的执行其他任务。当DMA结束后,DMAC通过中断通知CPU数据传输已经结束,由CPU执行相应的中断服务程序进行后续处理。

    本质上说DMA控制器就是主板上一块独立的芯片,通过它来进行内存和IO设备的数据传输,从而减少CPU的等待时间。

   

  上下文切换:内核在CPU上对进程或者线程进行切换。基本原理是,当发生任务切换时,保存当前任务的寄存器到进程控制块(PCB,Process Control Block)中,将下一个即将要切换过来的任务的寄存器状态恢复到当前CPU寄存器中,使其继续执行,同一时刻只允许一个任务独享寄存器。

    上下文的切换流程如下 :

    (1)挂起一个进程,将这个进程在CPU中的状态(上下文信息)存储于内存的PCB中。 
    (2)在PCB中检索下一个进程的上下文并将其在CPU的寄存器中恢复。 
    (3)跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行)并恢复该进程

  从Linux系统上看,除了引导系统的BIN区,整个内存空间主要分为两个部分:内核空间、用户空间

    内核空间是Linux自身使用的内存空间,主要提供给程序调度、内存分配、连接硬件等程序逻辑使用;

    用户空间则是提供给各个进程的主要空间。

    用户空间不具有访问内核空间资源的权限,因此如果应用程序需要使用到内核空间的资源,则需要通过系统调用来完成(也就是调用操作系统内核提供的API):进行上下文切换,从用户空间切换到内核空间,然后在完成相关操作后再从内核空间切换回用户空间。

  当程序请求网络数据的时候,需要经历两次拷贝:

    ①:程序需要等待数据从网卡拷贝到内核空间

    ②:因为用户程序无法访问内核空间,所以内核又得把数据拷贝到用户空间,这样处于用户空间的程序才能访问这个数据

 2、什么是零拷贝

  零拷贝技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。

  简单来说就是减少和避免不必要的CPU数据拷贝过程,从而减少拷贝的CPU的开销及用户态和内核态之间的切换次数,从而优化数据传输的性能。

  这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽

  几种零拷贝实现思路:

    1)直接IO:数据直接跨过内核,在用户空间和IO设备之间传递,内核只是进行必要的虚拟存储配置等辅助工作

    2)避免内核和用户空间之间的数据拷贝:当用户空间不需要对数据进行访问时,则可以避免将数据从内核空间拷贝到用户空间(如sendfile方式)

    3)写时复制:数据不需要提前拷贝,而是当需要修改的时候再进行部分拷贝

  1)传统IO方式

    传统的IO方式,底层实际上通过调用read()和write()来实现。通过read() 把数据从硬盘读取到内核缓冲区,再复制到用户缓冲区;然后再通过write()写入到Socket缓冲区,最后写入网卡设备。

    什么是零拷贝第1张

    DMA Copy不需要CPU全程参与,CPU Copy需要CPU全程参与。

    读操作:

      ①:用户进程通过read()方法向操作系统发起调用;此时上下文从用户态切换为内核态

      ②:DMA控制器把数据从硬盘中拷贝到内核的读缓存区,发生一次DMA Copy

      ③:CPU把内核读缓存区数据拷贝到应用缓冲区,发生了一次CPU Copy

      ④:read调用返回后,上下文再次从内核态切换为用户态

      发生两次上下文切换,两次Copy

    写操作:

      ①:用户进程通过write()方法发起调用,上下文从用户态切换为内核态 

      ②:CPU将应用缓冲区的数据Copy到内核的Socket缓冲区

      ③:DMA控制器把数据从Socket缓冲区Copy到网卡(或其他存储设备)

      ④:写入结束后返回,上下文从内核态切换回用户态

      发生两次上下文切换,两次Copy

    传统的IO读写操作,总共进行了4次上下文切换,4次Copy动作。数据在内核空间和应用空间之间来回复制,严重消耗资源。

    4次Copy如下:

      ①:读取磁盘文件到操作系统内核缓冲区(DMA Copy)

      ②:将内核缓冲区的数据Copy到应用程序缓冲区(CPU Copy)

      ③:将应用程序缓冲区的数据,Copy到内核Socket网络发送缓冲区(CPU Copy)

      ④:将内核Socket缓冲区的数据Copy到网卡(DMA Copy)

    注意:为了程序和系统安全考虑,操作系统为每个应用程序都设计了用户内存,且用户内存和内核内存是隔离的。这也是需要从应用程序缓冲区到内核缓冲区来回复制的原因了。

  

    虚拟内存技术

    虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行交换。

    背景:电脑中所运行的程序均需由经过内存执行,若执行的程序占用内存很大或很多,则会导致内存消耗殆尽。为解决该问题,window中运用了虚拟内存技术(linux中成为交换空间),即匀出一部分硬盘空间来充当内存使用。当内存耗尽时,电脑就会自动调用硬盘来充当内存,以缓解内存的紧张。

    所有现代操作系统都使用虚拟内存,使用虚拟地址取代物理地址,这样做的好处就是:

      1、多个虚拟内存可以指向同一个物理地址

      2、虚拟内存空间可以远远大于物理内存空间

   使用虚拟内存技术将内核空间和用户空间的虚拟地址映射到同一个物理地址,这样就不用在程序和内核之间来回复制。传统的IO操作经过虚拟地址优化后就省去了上面的CPU copy:

什么是零拷贝第2张

   

   2) mmap+write方式

    mmap:一种内存映射文件的方法,将一个或者其他对象映射进内存

    使用mmap+write方式替换原来的传统IO方式,就是利用了虚拟内存的特性,mmap+write的IO读写过程:

    什么是零拷贝第3张

     整体流程的核心区别就是,把数据读取到内核缓冲区后,应用程序进行写入操作时,直接把内核的Read Buffer的数据复制到Socket Buffer以便进行写入,这次内核之间的复制也是需要CPU参与的。

    与传统的IO流程相比,少了一次CPU Copy,不过上下文切换还是4次(4次上下文切换,3次Copy

    mmap+write方式减少了CPU的使用,适用于大文件的传输。

    

   3)sendfile方式

    相比mmap来说,sendfile同样减少了一次CPU Copy,而且减少了2次上下文切换。

    sendfile是Linux2.1内核版本后引入的一个系统调用函数,通过使用sendfile数据可以直接在内核空间进行传输,因此避免了用户空间和内核空间的拷贝,流程如下:

什么是零拷贝第4张

    

    整个过程发生了2次用户态和内核态的上下文切换和3次拷贝,具体流程如下:

     1)用户进程通过sendfile()方法向操作系统发起调用,上下文从用户态转向内核态
     2)DMA控制器把数据从硬盘中拷贝到读缓冲区
     3)CPU将读缓冲区中数据拷贝到socket缓冲区
     4)DMA控制器把数据从socket缓冲区拷贝到网卡,上下文从内核态切换回用户态,sendfile调用返回


    sendfile方法IO数据对用户空间完全不可见,所以只能适用于完全不需要用户空间处理的情况,比如静态文件服务器

    

  应用:

  RocketMQ和Kafka都使用了零拷贝的技术

  对于MQ,整个流程为:生产者发送数据到MQ,然后持久化到磁盘,之后消费者从磁盘读取数据。

  对于RocketMQ来说这两个步骤使用的是mmap+write,而Kafka则是使用mmap+write持久化数据,发送数据使用sendfile

    

  总结:

  由于CPU和IO速度的差异问题,产生了DMA技术,通过DMA搬运来减少CPU的等待时间。

  传统的IO read+write方式会产生2次DMA拷贝+2次CPU拷贝,同时有4次上下文切换。

  而通过mmap+write方式则产生2次DMA拷贝+1次CPU拷贝,4次上下文切换,通过内存映射减少了一次CPU拷贝,可以减少内存使用,适合大文件的传输。

  sendfile方式是新增的一个系统调用函数,产生2次DMA拷贝+1次CPU拷贝,但是只有2次上下文切换。因为只有一次调用,减少了上下文的切换,但是用户空间对IO数据不可见,适用于静态文件服务器

  

  参考:

  https://mp.weixin.qq.com/s/yvenw3P2JvvSxWodBNNcMw

  https://www.jianshu.com/p/e76e3580e356

  https://blog.51cto.com/12182612/2424692?source=dra

END.

免责声明:文章转载自《什么是零拷贝》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转】彻底掌握Quartus——基础篇android logd 原理及实现下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JVM内存结构、垃圾回收那点事(转)

翻看电脑的文件夹,无意看到了9月份在公司做的一次分享,浏览了一下"婆婆特",发现自己在ppt上的写的引导性问题自己也不能确切的回答出来,哎,知识这东西,平时不常用的没些日子就生疏了。于是,本小白决定把他整理下来,不敢班门弄斧,对于入门的同学可以快速了解虚拟机的大概,有错误的地方请批评指正。 一、java虚拟机的内存结构     方法区:线程共享,存放已被...

Elasticsearch学习之深入聚合分析五---案例实战

1. fielddata核心原理   fielddata加载到内存的过程是lazy加载的,对一个analzyed field执行聚合时,才会加载,而且是field-level加载的,一个index的一个field,所有doc都会被加载,而不是少数doc,不是index-time创建,是query-time创建 2. fielddata内存限制   indi...

也谈同步异步I/O

也谈同步异步I/O [转自: http://www.smithfox.com/?e=191 ] I/O Model 是一个很大的话题, 也是一个实践性很强的事情, 网上有各种说法和资料, 我们必须用辩证的态度去看待(包括本Blog :) ), 因为有的信息是过时的, 有些则可能是未经实践的片面的理解. 为避免走题(走到 高并发问题 上去了), 本次讨论作了...

linux性能评估-cpu案例操作篇

1.平均负载案例分析 场景一:CPU 密集型进程 场景二:I/O密集型进程 场景三:大量进程的场景 2.CPU 上下文切换案例 2.1怎么查看系统的上下文切换情况 2.2查看每个进程上下文切换的情况 2.3 案例实操 3.CPU使用率的案例 3.1CPU 使用率很高,但为啥却找不到高 CPU 的应用? 3.2 等待 I/O 的 CPU的使用...

操作系统——进程,线程,锁

基本概念 状态、地址空间 三种基本状态 —— 就绪、运行、阻塞 进程控制块PCB(Process Control Block) 进程描述信息(如PID); 进程控制&管理信息(状态、优先级等); 源分配清单(地址空间状况、fd等); 处理其相关信息(各寄存器的值等) 进程存在的标识,在Linux系统中是task_struct,task_s...

机器CPU load过高问题排查

load average的概念 系统平均负载定义:在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少进程)的平均进程数。如果一个进程满足以下条件则其就会位于运行队列中: 它没有在等待I/O操作的结果 它没有主动进入等待状态(也就是没有调用’wait’) 没有被停止(例如:等待终止) 在Linux中,进程分为三种状态,一种是阻塞的进程blocke...