零拷贝和应用
1.什么是零拷贝
零拷贝不是没有拷贝数据, 而是
减少用户态, 内核态的切换次数 和 CPU拷贝次数
2. 传统IO

3. 实现方式
3.1.mmap + write
虚拟内存把内核空间和用户空间的虚拟地址映射到同一个物理地址, 从而减少数据拷贝次数,
mmap技术就是利用了虚拟内存的这个特点, 它将内核中的读缓冲区与用户空间的缓冲区进行映射, 所有的IO操作都在内核中完成

-
用户进程通过
mmap方法向操作系统内核发起 IO 调用,上下文从用户态切换为内核态。 -
CPU 利用
DMA控制器,把数据从硬盘中拷贝到内核缓冲区。 -
上下文从内核态切换回用户态,
mmap方法返回。 -
用户进程通过write 方法向操作系统内核发起IO 调用,上下文从用户态切换为内核态。
-
CPU 将内核缓冲区的数据拷贝到的 socket 缓冲区。
-
CPU 利用
DMA控制器,把数据从 socket 缓冲区拷贝到网卡,上下文从内核态切换回用户态,write 调用返回。
mmap+write 实现的零拷贝,I/O 发生了4次用户空间与内核空间的上下文切 换,以及3 次数据拷贝(包括了2次DMA拷贝和1 次CPU 拷贝)。
3.2 sendfile
sendfile表示在两个文件描述符之间传输数据,它是在操作系统内核中操作的, 避免了数据从内核缓冲区和用户缓冲区之间的拷贝操作

-
用户进程发起·
sendfile系统调用,上下文(切换 1)从用户态转向内核态 -
DMA控制器,把数据从硬盘中拷贝到内核缓冲区。 -
CPU将读缓冲区中数据拷贝到 socket 缓冲区 -
DMA控制器,异步把数据从 socket 缓冲区拷贝到网卡, -
上下文(切换2)从内核态切换回用户态,
sendfile调用返回。
2次上下文切换,2次DMA拷贝,一次cpu 拷贝
3.3 带DMA收集功能sendfile (sendfile+DMA Scatter/Gather)
linux 2.4版本之后,对sendfile做了优化升级,引入SG-DMA技术,其实就是对DMA拷贝加入了scatter/gather操作,它可以直接从内核空间缓冲区中将数据读取到网卡。使用这个特点搞零拷贝,即还可以多省去一次CPU拷贝。

-
用户进程发起
sendfile系统调用,上下文(切换1)从用户态转向内核态 -
DMA控制器,把数据从硬盘中拷贝到内核缓冲区。 -
CPU把内核缓冲区中的文件描述符信息(包括内核缓冲区的内存地址和偏移量)发送到socket缓冲区
-
DMA控制器根据文件描述符信息,直接把数据从内核缓冲区拷贝到网卡 -
上下文(切换2)从内核态切换回用户态,
sendfile调用返回。
可以发现,sendfile+DMA scatter/gather实现的零拷贝,I/O发生了2次用户空间与内核空间的上下文切换,以及2次数据拷贝。其中2次数据拷贝都是包DMA拷贝。这就是真正的 零拷贝(Zero-copy) 技术,全程都没有通过CPU来搬运数据,所有的数据都是通过DMA来进行传输的。
4. DMA 技术说明
DMA,英文全称是Direct Memory Access,即直接内存访问。DMA本质上是一块主板上独立的芯片,允许外设设备和内存存储器之间直接进行IO数据传输,其过程不需要CPU的参与。

5.应用场景
RocketMQ和Kafka都使用到了零拷贝的技术。
对于MQ而言,无非就是生产者发送数据到MQ然后持久化到磁盘,之后消费者从MQ读取数据。
对于RocketMQ来说这两个步骤使用的是mmap+write,而Kafka则是使用mmap+write持久化数据,发送数据使用sendfile
6.java对零拷贝支持
6.1 Java NIO对mmap的支持
MappedByteBuffer
6.2 Java NIO对sendfile的支持
FileChannel的transferTo()/transferFrom(),底层就是sendfile() 系统调用函数

浙公网安备 33010602011771号