零拷贝学习总结

前段时间重温nginx的源码,涉及到了sendfile的配置,去看了下零拷贝这块的相关知识,收集了一些网络的讲解和资源,做下汇总,以供自己后续回顾。

1 什么是零拷贝

维基百科的解释: 计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽

正常一次文件的读写都会涉及到用户空间、内核空间、硬盘空间这三块的交互,一次完整的读取过程将会产生4次上下文切换和4次数据拷贝。

而零拷贝的目标就是消除这些多余的拷贝来提升性能的。

在数据传输的过程中,避免数据在内核空间缓冲区和用户空间缓冲区之间进行拷贝,以及数据在内核空间缓冲区内的CPU拷贝。

https://zh.wikipedia.org/wiki/%E9%9B%B6%E5%A4%8D%E5%88%B6

2 Linux零拷贝技术

此处主要参考的是《深入理解Linux内核》这本书中的第十六章“访问文件”而来 其中提到几种零拷贝的技术,包括内存映射模式、直接I/O传送、异步I/O

2.1 内存映射

在数据传输的过程中,避免数据在操作系统内核地址空间的缓冲区和用户应用程序地址空间的缓冲区之间进行拷贝。有的时候,应用程序在数据进行传输的过程中不需要对数据进行访问,那么,将数据从 Linux 的页缓存拷贝到用户进程的缓冲区中就可以完全避免,传输的数据在页缓存中就可以得到处理。在某些特殊的情况下,这种零拷贝技术可以获得较好的性能。Linux 中提供类似的系统调用主要有 mmap(),sendfile() 以及 splice()。

2.2 直接I/O传送

对于这种数据传输方式来说,应用程序可以直接访问硬件存储,操作系统内核只是辅助数据传输:这类零拷贝技术针对的是操作系统内核并不需要对数据进行直接处理的情况,数据可以在应用程序地址空间的缓冲区和磁盘之间直接进行传输,完全不需要 Linux 操作系统内核提供的页缓存的支持。

在每次I/O直接传送中,内核对磁盘控制器进行编程,以便在自缓存的应用程序的用户态地址空间中的页与磁盘之间直接传送数据。

2.3 异步I/O

对数据在 Linux 的页缓存和用户进程的缓冲区之间的传输过程进行优化。

此处有一个重要的数据结构:AIO环。AIO环是用户态进程中地址空间的内存缓冲区,它也可以由内核态的所有进程访问。

3 零拷贝在各个服务中的应用

3.1 Nginx

Nginx通过使用sendfile指令来控制是不是用linux提供的零拷贝功能。 具体配置如下:

sendfile on/off

该指令主要用在http框架下。

3.2 Kafka

Kafka把所有的消息都变成一个个的文件。

  • 写入数据的时候是顺序写入,所以速度最优
  • 读取数据的时候通过mmap提高I/O速度,配合sendfile进行输出

3.3 其他服务

  • Netty
  • Apache
  • Lighttpd

相关学习链接