一文让你彻底搞清楚,Linux零拷贝技术的那些事儿( 二 )


我们需要降低冗余数据拷贝、解放CPU,这也就是零拷贝Zero-Copy技术 。
4.2 解决思路目前来看,零拷贝技术的几个实现手段包括:mmap+write、sendfile、sendfile+DMA收集、splice等 。

一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 
4.2.1 mmap方式mmap是Linux提供的一种内存映射文件的机制,它实现了将内核中读缓冲区地址与用户空间缓冲区地址进行映射,从而实现内核缓冲区与用户缓冲区的共享 。
这样就减少了一次用户态和内核态的CPU拷贝,但是在内核空间内仍然有一次CPU拷贝 。
一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 
【一文让你彻底搞清楚,Linux零拷贝技术的那些事儿】mmap对大文件传输有一定优势,但是小文件可能出现碎片,并且在多个进程同时操作文件时可能产生引发coredump的signal 。
4.2.2 sendfile方式mmap+write方式有一定改进,但是由系统调用引起的状态切换并没有减少 。
sendfile系统调用是在 Linux 内核2.1版本中被引入,它建立了两个文件之间的传输通道 。
sendfile方式只使用一个函数就可以完成之前的read+write 和 mmap+write的功能,这样就少了2次状态切换,由于数据不经过用户缓冲区,因此该数据无法被修改 。
一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 

一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 
从图中可以看到,应用程序只需要调用sendfile函数即可完成,只有2次状态切换、1次CPU拷贝、2次DMA拷贝 。
但是sendfile在内核缓冲区和socket缓冲区仍然存在一次CPU拷贝,或许这个还可以优化 。
4.2.3 sendfile+DMA收集Linux 2.4 内核对 sendfile 系统调用进行优化,但是需要硬件DMA控制器的配合 。
升级后的sendfile将内核空间缓冲区中对应的数据描述信息(文件描述符、地址偏移量等信息)记录到socket缓冲区中 。
DMA控制器根据socket缓冲区中的地址和偏移量将数据从内核缓冲区拷贝到网卡中,从而省去了内核空间中仅剩1次CPU拷贝 。
一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 
这种方式有2次状态切换、0次CPU拷贝、2次DMA拷贝,但是仍然无法对数据进行修改,并且需要硬件层面DMA的支持,并且sendfile只能将文件数据拷贝到socket描述符上,有一定的局限性 。
4.2.4 splice方式splice系统调用是Linux 在 2.6 版本引入的,其不需要硬件支持,并且不再限定于socket上,实现两个普通文件之间的数据零拷贝 。
一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 
splice 系统调用可以在内核缓冲区和socket缓冲区之间建立管道来传输数据,避免了两者之间的 CPU 拷贝操作 。
一文让你彻底搞清楚,Linux零拷贝技术的那些事儿

文章插图
 
splice也有一些局限,它的两个文件描述符参数中有一个必须是管道设备 。
 
5.本文小结本文通过介绍数据交互的基本过程、传统模式的缺点,进而介绍了零拷贝的一些实现方法 。
零拷贝技术是非常底层且重要的读写优化,对于服务并发能力的提升有很大帮助,就这么多吧,下期再见!




推荐阅读