Linux从零单排之零拷贝(一)
- Linux
- 14天前
- 11热度
- 0评论
第三章:三种方式对比 —— 从传统到零拷贝
在本章节中,我们将详细比较四种文件传输方式的性能和适用场景。这包括传统的 read/write 方法、使用 mmap + write 的方法以及 Linux 内核提供的 sendfile 和 splice 管道零拷贝技术。
3.1 四种文件传输方式对比
以下是四种不同的文件传输方式的简要概述,重点在于数据拷贝次数和上下文切换情况:
| 文件传输方式 | 数据拷贝次数 | 上下文切换次数 | CPU 参与情况 | 推荐场景 |
|---|---|---|---|---|
| 传统 read/write | 4 | 4 | 是 | 通用,简单 |
| mmap + write | 3 | 4 | 是 | 需要访问文件内容 |
| sendfile | 2 | 2 | 否 | 文件发送,最优 |
| splice 管道零拷贝 | 0 | 2 | 否 | 管道/套接字间传输 |
3.2 详细对比表
下面是对这四种方法的详细描述和比较:
| 方式 | 数据拷贝次数 (CPU 参与) | 上下文切换次数 | CPU 参与情况 | 适用场景 |
|---|---|---|---|---|
| 传统 read/write | 4 次(包括用户态到内核、内核到页缓存、内核到用户态) | 4 | 是 | 文件读写操作,通用且简单 |
| mmap + write | 3 次(用户态到内核缓冲区,DMA 到磁盘,DMA Gather 收集数据到 Socket 缓冲区) | 4 | 是 | 需要访问文件内容 |
| sendfile | 2 次(DMA 从页缓存读取磁盘数据、DMA 将数据发送至网卡缓冲区) | 2 | 否 | 文件发送,性能最优 |
| splice 管道零拷贝 | 0 次(直接使用内核空间进行 DMA 操作,无需 CPU 参与) | 2 | 否 | 管道/套接字间数据传输 |
3.3 数据流向架构图
为了更直观地理解这些方法的工作原理和数据流向:
sendfile(DMA Gather 技术):直接从磁盘读取到页缓存,然后通过 DMA 机制将分段的地址信息传递给网卡发送数据。这种方式省去了用户态的干预,只有两次上下文切换。

mmap + write:使用 mmap 将文件映射到内存中,然后通过 write 系统调用将数据发送到套接字。这种方式需要三次数据拷贝和四次上下文切换。

传统 read/write:传统的读写方法,涉及用户态与内核态之间的多次数据传输,并且每次传输都需要进行一次上下文切换。这种方式最为耗时和资源消耗大。

splice 管道零拷贝:利用 splice 将文件描述符之间的数据传递直接在内核空间完成,不涉及用户态操作。这种方式仅需两次上下文切换,并且没有实际的数据拷贝。

通过上面的对比和图示可以看出,sendfile 和 splice 是实现零拷贝传输的最佳方式,在文件发送或管道间数据传输场景中表现尤为突出。它们减少了 CPU 的参与以及上下文切换次数,从而显著提高了性能。
总结
在现代高性能网络应用开发过程中,采用如 sendfile 或 splice 这样的零拷贝技术可以显著提高系统吞吐量和响应速度,在文件传输或管道间数据传递时尤为适用。而传统的读写方法虽然简单直接,但其性能远不如这些现代的零拷贝技术。
通过选择合适的文件传输方式,开发者能够构建出更为高效、可扩展的应用程序,特别是在处理大量并发请求或者大流量数据传输场景下尤为重要。
第四章:深入理解 —— 零拷贝技术详解
4.1 mmap 系统调用原理
mmap 是一个强大的系统调用,允许用户直接访问文件内容,而不需要通过常规的读写操作。它在内核中建立了一个页表映射,使得文件可以直接被当作内存来访问。
优点:
- 减少拷贝次数:文件数据不在内核和用户空间之间进行复制。
- 高效读取:直接从磁盘加载到用户进程的虚拟地址空间中,减少了缓存层的数据传输。
- 简化编程模型:开发者可以直接操作映射内存,无需关心复杂的 I/O 操作。
缺点:
- 潜在缺页中断:如果文件被部分映射,则未映射的部分可能会导致缺页故障。
- 内存消耗大:对于大型文件,可能需要占用大量虚拟地址空间。
4.2 sendfile 系统调用原理
sendfile 是一个特殊的设计用于减少数据拷贝次数的系统调用。它允许内核直接从磁盘读取文件内容并发送到网络套接字,而不需要通过用户进程的空间进行中间存储。
优点:
- 高效传输:绕过了用户空间的缓冲区,减少了 CPU 参与的数据处理。
- 简化代码逻辑:减轻了应用层的负担,减少了系统调用次数和上下文切换开销。
缺点:
- 限制于特定协议:只能直接适用于支持该系统的网络套接字类型(如 UNIX 套接字和 TCP)。
- 性能瓶颈:对于小文件传输效率较低,因为内核需要额外处理细节来优化。
4.3 splice 和 tee 系统调用
splice 和 tee 是另一种实现零拷贝的技术。它们允许在管道之间或与套接字之间的数据移动时减少复制操作。
splice
- 在两个文件描述符之间传输数据,通常用于管道和文件。
- 优点:适用于大流量的流式数据处理。
tee
- 允许将输入的一部分复制到输出,并同时传递剩余的数据(分叉)。
- 优点:支持复杂的数据流转操作。
4.4 使用场景与注意事项
选择何种零拷贝技术取决于具体的使用场景:
| 技术 | 场景 |
|---|---|
| mmap | 需要频繁读写文件的场合,如数据库缓存、内存映射共享库等。 |
| sendfile | 文件传输和网络服务器(例如 Nginx 和 Apache)等,尤其是大文件的直接发送。 |
| splice/tee | 流式数据处理,管道传输优化等场景。 |
在选择使用零拷贝技术时,还需要考虑以下几点:
- 安全性: 使用 mmap 时需要特别注意避免未映射页面导致的程序崩溃。
- 兼容性: 不同操作系统和内核版本可能对这些系统调用的支持程度不同。
- 性能评估:实际测试在目标硬件上的效果,确保应用收益大于投入。
结论
零拷贝技术通过减少不必要的数据复制操作来提高系统的整体效率。正确选择适当的零拷贝方法可以显著提升应用程序的性能和可扩展性,在设计时需综合考虑应用场景、系统资源及兼容性等因素。