[toc]
DMA#
Q:DMA的作用是什么?#
A:
IO中断,需要CPU响应,需要CPU参与,因此效率比较低
用户进程需要读取磁盘数据,需要CPU中断,发起IO请求,每次的IO中断,都带来CPU的上下文切换。
DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU 的大量中断负载。
实际因此IO读取,涉及两个过程:
- DMA等待数据准备好,把磁盘数据读取到操作系统内核缓冲区;
- 用户进程,将内核缓冲区的数据copy到用户空间。
这两个过程,都是阻塞的,占用时间。
传统数据传送#
Q: 传统数据传送的缺点是什么?
A: 如果是把文件二进制数据直接通过网络传输, 会涉及4次传输。
- 第一次:将磁盘文件,读取到操作系统内核缓冲区;
- 第二次:将内核缓冲区的数据,copy到application应用程序的buffer;
- 第三步:将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区);
- 第四次:将socket buffer的数据,copy到网卡,由网卡进行网络传输。
如果不对数据做特殊处理的话, 那么2和3是没有必要的。
零拷贝原理#
什么是零拷贝?#
零拷贝(英语: Zero-copy) 技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。
- 零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,从而有效地提高数据传输效率
- 零拷贝技术减少了用户进程地址空间和内核地址空间之间因为上:下文切换而带来的开销
可以看出没有说不需要拷贝,只是说减少冗余[不必要]的拷贝。
目的:减少IO流程中不必要的拷贝
零拷贝需要OS支持,也就是需要kernel暴露api。虚拟机不能操作内核,
一、mmap内存映射#
DMA加载磁盘数据到kernel buffer后,应用程序缓冲区(application buffers)和内核缓冲区(kernel buffer)进行映射,数据再应用缓冲区和内核缓存区的改变就能省略。
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里的数据就能在网络传输了。
sendfile会经历:3次拷贝,1次CPU copy 2次DMA copy;
以及2次上下文切换
三、、Sendfile With DMA Scatter/Gather Copy#
Scatter/Gather可以看作是sendfile的增强版,批量sendfile。
浅谈scatter-gather DMA
Scatter/Gather会经历2次拷贝: 0次cpu copy,2次DMA copy
为什么都是sendfile, scatter/gather不需要cpu拷贝呢?
我理解是copy过程借助的是DMA的gathercopy, 不再需要cpu的参与, 他可以一次性全部拷贝完,不用分多次。
四、splice#
数据从磁盘读取到OS内核缓冲区后,在内核缓冲区直接可将其转成内核空间其他数据buffer,而不需要拷贝到用户空间。
如下图所示,从磁盘读取到内核buffer后,在内核空间直接与socket buffer建立pipe管道。
和sendfile()不同的是,splice()不需要硬件支持。
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 零拷贝机制对比#
零拷贝的应用#
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。