1、什么是零拷贝
零拷贝(zero-copy)技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节点CPU的周期和内存带宽。
零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,从而有效地提高数据传输效率。
零拷贝技术减少了用户进程地址空间和内核地址空间之间因为上下文切换而带来的开销。
可以看出零拷贝不是不需要拷贝,只是说减少冗余的拷贝。
以下组件、框架中使用了零拷贝技术:kafka、netty、rocketmq、nginx、es
2、Linux的I/O机制与DMA
在早期的计算机中,用户进程需要读取磁盘数据,需要cpu中断和cpu参与,因此效率比较低,发起io请求,每次的io中断,都带来cpu的上下文的切换,因此出现了DMA。
DMA(Direct Memory Access)直接内存存取是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于cpu的大量中断负载。DMA控制器,接管了数据的读写请求,减少cpu的负担。这样一来,cpu效级提高了,现代硬盘基于都支持DMA。
实际IO读取,涉及两个过程:
DMA等待数据准备好,把磁盘数据读取到操作系统内核缓冲区;
用户进程,将内核缓存区的数据copy到用户空间。
这两个过程,都是阻塞的。
3、传统数据传送机制
比如:读取文件,再用socket发送出去,实际经过四次copy.
buffer = File.read();
Socket.send(buffer);
第一步:将磁盘文件读取到操作系统内核缓冲区;
第二步:将内核缓冲区的数据,copy到应用程序的buffer;
第三步:将应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区);
第四步:将socket buffer数据,copy到网卡,由网卡进行网络传输;
分析上述的过程,虽然引入DMA来接管cpu的中断请求,但四次copy是存在“不必要的拷贝的”,实际上并不需要第二个和第三个数据副本,应用程序除了缓存数据并将期传输加套接字缓冲区之外什么都不做。相反,数据可以直接从读缓冲区传输到套接字缓存区。
显然,第二次和第三次数据copy其实在这种场景下没有什么帮助反而带来开销,这也正是零拷贝的背景和意义。
4、sendfile零拷贝
linux2.1开始支持sendfile
当调用sendfile()时,DMA将磁盘数据复制到kernel buffer,然后将内核中的kernel buffer直接拷贝到socket buffer。在硬件支持的情况下,甚至数据并不需要被真正复制到socket关联的缓冲区,取而代之的是,只有记录数据位置和长度描述符被加入到socket缓冲区,DMA模式将数据直接从内核缓冲区传递给协议引擎,从而消除了遗留的最后一次复制(CPU copy)。
一旦数据全都拷贝到了socket buffer,sendfile()系统调用将会return、代表数据转化的完成。socket buffer里的数据就能在网络传输了。
sendfile会经历:3次拷贝,1次CPU copy,2次DMA copy;