Linux零拷贝技术,看完这篇文章就懂了


Linux零拷贝技术,看完这篇文章就懂了

文章插图
本文讲解 linux 的零拷贝技术 , 云计算是一门很庞大的技术学科 , 融合了很多技术 , Linux 算是比较基础的技术 , 所以 , 学好 Linux 对于云计算的学习会有比较大的帮助 。
本文借鉴并总结了几种比较常见的 Linux 下的零拷贝技术 , 相关的引用链接见文后 , 大家如果觉得本文总结得太抽象 , 可以转到链接看详细解释 。
 
为什么需要零拷贝传统的 Linux 系统的标准 I/O 接口(read、write)是基于数据拷贝的 , 也就是数据都是 copy_to_user 或者 copy_from_user , 这样做的好处是 , 通过中间缓存的机制 , 减少磁盘 I/O 的操作 , 但是坏处也很明显 , 大量数据的拷贝 , 用户态和内核态的频繁切换 , 会消耗大量的 CPU 资源 , 严重影响数据传输的性能 , 有数据表明 , 在Linux内核协议栈中 , 这个拷贝的耗时甚至占到了数据包整个处理流程的57.1% 。
 
什么是零拷贝零拷贝就是这个问题的一个解决方案 , 通过尽量避免拷贝操作来缓解 CPU 的压力 。Linux 下常见的零拷贝技术可以分为两大类:一是针对特定场景 , 去掉不必要的拷贝;二是去优化整个拷贝的过程 。由此看来 , 零拷贝并没有真正做到“0”拷贝 , 它更多是一种思想 , 很多的零拷贝技术都是基于这个思想去做的优化 。
Linux零拷贝技术,看完这篇文章就懂了

文章插图
 
零拷贝的几种方法原始数据拷贝操作在介绍之前 , 先看看 Linux 原始的数据拷贝操作是怎样的 。如下图 , 假如一个应用需要从某个磁盘文件中读取内容通过网络发出去 , 像这样:
while((n = read(diskfd, buf, BUF_SIZE)) > 0)write(sockfd, buf , n);那么整个过程就需要经历:1)read 将数据从磁盘文件通过 DMA 等方式拷贝到内核开辟的缓冲区;2)数据从内核缓冲区复制到用户态缓冲区;3)write 将数据从用户态缓冲区复制到内核协议栈开辟的 socket 缓冲区;4)数据从 socket 缓冲区通过 DMA 拷贝到网卡上发出去 。
Linux零拷贝技术,看完这篇文章就懂了

文章插图
可见 , 整个过程发生了至少四次数据拷贝 , 其中两次是 DMA 与硬件通讯来完成 , CPU 不直接参与 , 去掉这两次 , 仍然有两次 CPU 数据拷贝操作 。
 
方法一:用户态直接 I/O这种方法可以使应用程序或者运行在用户态下的库函数直接访问硬件设备 , 数据直接跨过内核进行传输 , 内核在整个数据传输过程除了会进行必要的虚拟存储配置工作之外 , 不参与其他任何工作 , 这种方式能够直接绕过内核 , 极大提高了性能 。
Linux零拷贝技术,看完这篇文章就懂了

文章插图
缺陷:
1)这种方法只能适用于那些不需要内核缓冲区处理的应用程序 , 这些应用程序通常在进程地址空间有自己的数据缓存机制 , 称为自缓存应用程序 , 如数据库管理系统就是一个代表 。
2)这种方法直接操作磁盘 I/O , 由于 CPU 和磁盘 I/O 之间的执行时间差距 , 会造成资源的浪费 , 解决这个问题需要和异步 I/O 结合使用 。
 
方法二:mmap这种方法 , 使用 mmap 来代替 read , 可以减少一次拷贝操作 , 如下:
buf = mmap(diskfd, len);write(sockfd, buf, len);应用程序调用 mmap  , 磁盘文件中的数据通过 DMA 拷贝到内核缓冲区 , 接着操作系统会将这个缓冲区与应用程序共享 , 这样就不用往用户空间拷贝 。应用程序调用write  , 操作系统直接将数据从内核缓冲区拷贝到 socket 缓冲区 , 最后再通过 DMA 拷贝到网卡发出去 。
Linux零拷贝技术,看完这篇文章就懂了

文章插图
缺陷:
1)mmap 隐藏着一个陷阱 , 当 mmap 一个文件时 , 如果这个文件被另一个进程所截获 , 那么 write 系统调用会因为访问非法地址被 SIGBUS 信号终止 , SIGBUS 默认会杀死进程并产生一个 coredump , 如果服务器被这样终止了 , 那损失就可能不小了 。


推荐阅读