什么是零拷贝及实现方式?

传统I/O有性能问题。

数据拷贝

  • 在传统 I/O 中,数据的传输通常涉及多次数据拷贝。

  • 数据需要从应用程序的用户缓冲区复制到内核缓冲区,然后再从内核缓冲区复制到设备或网络缓冲区。

  • 这些数据拷贝过程导致了多次内存访问和数据复制,消耗了大量的 CPU 时间和内存带宽。

用户态和内核态的切换

  • 由于数据要经过内核缓冲区,导致数据在用户态和内核态之间来回切换,切换过程中会有上下文的切换。

零拷贝技术用来解决以上问题。

image-20231011095850049

实现零拷贝的技术主要有两种:mmap+write,sendfile

mmap+write

利用mmap替换read系统调用函数。

mmap系统调用函数会直接将内核缓冲区的数据映射到用户空间,这样操作系统内核与用户空间之间就不需要任何的拷贝操作。

image-20231011095850049

具体流程:

  • 应用进程调用了mmap系统调用函数之后,DMA会把磁盘缓冲区的数据拷贝到内核缓冲区中。

  • 接着,应用进程和操作系统内核共享这个缓冲区。

  • 应用进程再调用write函数,操作系统直接将内核缓冲区的数据拷贝到socket缓冲区。

  • 再由DMA控制器copy到网卡。

这还不是最理想的零拷贝因为还是需要两次系统调用,四次上下文切换,3次拷贝。

sendfile

在linux内核版本2.1中,提供了一个新的系统调用函数sendfile。

  • 这个系统调用函数可以代替read和write两个系统调用函数。

通过 sendfile,应用程序可以直接将文件数据从文件系统传输到网络套接字或者目标文件,而无需经过用户缓冲区和内核缓冲区。

image-20231011095850049

这样系统调用的次数就变成了一次,上下文切换的次数减小到了两次,数据拷贝次数为3次。

如果网卡支持SG—DMA,就可以将数据拷贝次数减小为两次。

DMA(直接内存访问) 是一种硬件特性,允许外设(如网络适配器、磁盘控制器等)直接访问系统内存,而无需通过 CPU 的介入。

在数据传输时,DMA 可以直接将数据从内存传输到外设。

或者从外设传输数据到内存,避免了数据在用户态和内核态之间的多次拷贝。

image-20231011095850049

没有在内存层面区拷贝数据,全过程都没有使用CPU搬运数据,所有数据都是通过DMA进行传输的。

整个过程只需要两次上下文的切换和两次数据拷贝。