零拷贝

主要是介绍零拷贝的两种技术原理

what

零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在IO读写过程中。

实际上,零拷贝是有广义和狭义之分,目前我们通常听到的零拷贝,包括上面这个定义减少不必要的拷贝次数都是广义上的零拷贝。其实了解到这点就足够了。

我们知道,减少不必要的拷贝次数,就是为了提高效率。那零拷贝之前,是怎样的呢?

传统IO

image-20210526193401096

传统IO

  1. 将磁盘文件,拷贝到操作系统内核缓冲区
  2. 将内核缓冲区的数据,拷贝到应用程序的buffer
  3. 将应用程序buffer中的数据,再拷贝到socket网络发送缓冲区(属于内核缓冲区)
  4. 将socket buffer数据,拷贝到网卡,由网卡进行网络传输

传统IO方式,读取磁盘文件进行网络发送,经过4次数据拷贝。但是第2、3次的拷贝明显没有什么帮助。

传统IO存在多次无效拷贝,还伴随着大量的上下文切换。

MMAP

image-20210526193525042

这种方式使用mmap()代替了read()

  1. 磁盘的数据通过DMA拷贝到内核缓冲区
  2. 操作系统把这块内核缓冲区与应用程序共享,避免了用户缓冲区和内核缓冲区的跨界复制
  3. 应用程序调用write()直接从内核缓冲区的内容拷贝到socket缓冲区
  4. 最后系统将socket的数据传输到网卡,由网卡进行传输

MMAP减少了一次拷贝,提升了效率,但是并不减少上下文切换的次数。

SendFile

image-20210526194611101

这种方式是使用sendfile代替了read+write操作

  1. 首先sendfile系统调用,通过DMA引擎将磁盘文件拷贝到内存缓冲区
  2. 在内核缓冲区,内核将数据拷贝到socket缓冲区
  3. 最后,DMA将数据从内核拷贝到网卡,由网卡传输

数据总共发生3次拷贝

对比

  1. 都是Linux内核提供,实现零拷贝的API
  2. sendfile是将读到内核缓冲区的数据,直接转到socket buffer,进行网络发送
  3. mmap是将磁盘文件读取到内核缓冲区后进行映射,和用户缓冲区共享数据,然后CPU在拷贝数据到socket buffer,进行网络发送

参考链接