0%

linux零拷贝

[toc]

来源参考

DMA#

Q:DMA的作用是什么?#

A:
IO中断,需要CPU响应,需要CPU参与,因此效率比较低
用户进程需要读取磁盘数据,需要CPU中断,发起IO请求,每次的IO中断,都带来CPU的上下文切换。
DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU 的大量中断负载。


实际因此IO读取,涉及两个过程:

  1. DMA等待数据准备好,把磁盘数据读取到操作系统内核缓冲区;
  2. 用户进程,将内核缓冲区的数据copy到用户空间。
    这两个过程,都是阻塞的,占用时间。
    9bc71cd4950d1563b41e145c834a7a02714125b7

传统数据传送#

Q: 传统数据传送的缺点是什么?

A: 如果是把文件二进制数据直接通过网络传输, 会涉及4次传输。

  1. 第一次:将磁盘文件,读取到操作系统内核缓冲区;
  2. 第二次:将内核缓冲区的数据,copy到application应用程序的buffer;
  3. 第三步:将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区);
  4. 第四次:将socket buffer的数据,copy到网卡,由网卡进行网络传输。

b81d9302d0571857e766209319deeb824473bd49

如果不对数据做特殊处理的话, 那么2和3是没有必要的。

零拷贝原理#

什么是零拷贝?#

零拷贝(英语: Zero-copy) 技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。

  • 零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,从而有效地提高数据传输效率
  • 零拷贝技术减少了用户进程地址空间和内核地址空间之间因为上:下文切换而带来的开销

可以看出没有说不需要拷贝,只是说减少冗余[不必要]的拷贝。

目的:减少IO流程中不必要的拷贝
零拷贝需要OS支持,也就是需要kernel暴露api。虚拟机不能操作内核,

一、mmap内存映射#

DMA加载磁盘数据到kernel buffer后,应用程序缓冲区(application buffers)和内核缓冲区(kernel buffer)进行映射,数据再应用缓冲区和内核缓存区的改变就能省略。
3fb0ac7085f297bc9ebc376ca0b813313c0b703b

mmap内存映射将会经历:3次拷贝: 1次cpu copy,2次DMA copy;

epoll中事件的传递用的是mmap

二、sendfile#

当调用sendfile()时,DMA将磁盘数据复制到kernel buffer,然后将内核中的kernel buffer直接拷贝到socket buffer;
一旦数据全都拷贝到socket buffer,sendfile()系统调用将会return、代表数据转化的完成。
socket buffer里的数据就能在网络传输了。
6bc1d3912c82b88534cca1582fb77446d1a45916
sendfile会经历:3次拷贝,1次CPU copy 2次DMA copy;
以及2次上下文切换

三、、Sendfile With DMA Scatter/Gather Copy#

Scatter/Gather可以看作是sendfile的增强版,批量sendfile。

dae3d6b62f5de10f215226d8a8790ecc7ee6db5b
49ca15a47fae3cad2a776b8fdd5c4b5099f1cf5e
浅谈scatter-gather DMA
Scatter/Gather会经历2次拷贝: 0次cpu copy,2次DMA copy

为什么都是sendfile, scatter/gather不需要cpu拷贝呢?
我理解是copy过程借助的是DMA的gathercopy, 不再需要cpu的参与, 他可以一次性全部拷贝完,不用分多次。
7941f2f9868b88a70c970e955c7ceff5495734cd

四、splice#

数据从磁盘读取到OS内核缓冲区后,在内核缓冲区直接可将其转成内核空间其他数据buffer,而不需要拷贝到用户空间。
如下图所示,从磁盘读取到内核buffer后,在内核空间直接与socket buffer建立pipe管道。
和sendfile()不同的是,splice()不需要硬件支持。
d24a7b4f5d20e931f5a4b6bd681f556b98a012c5
splice会经历 2次拷贝: 0次cpu copy 2次DMA copy;

注意splice和sendfile的不同,sendfile是将磁盘数据加载到kernel buffer后,需要一次CPU copy,拷贝到socket buffer。
而splice是更进一步,连这个CPU copy也不需要了,直接将两个内核空间的buffer进行set up pipe。

linux 零拷贝机制对比#

e44c722b8b1949c80cd6267f9abc23e5e78bd4f0

零拷贝的应用#

Q: 知道零拷贝用在哪些地方吗?
A:

  • NIO提供的内存映射 MappedByteBuffer ——Linux mmap()
  • NIO FileChannel.transferTo() —— Linux sendfile()
  • Kafka Producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入;
  • Kafka Customer从broker读取数据,采用sendfile,将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送。

  • mmap 适合小数据量读写,sendFile 适合大文件传输。
  • mmap 需要 4 次上下文切换,3 次数据拷贝;sendFile 需要 3 次上下文切换,最少 2 次数据拷贝。
  • sendFile 可以利用 DMA 方式,减少 CPU 拷贝,mmap 则不能(必须从内核拷贝到 Socket 缓冲区)。
  • 在这个选择上:rocketMQ 在消费消息时,使用了 mmap。kafka 使用了 sendFile。