system column十三Tech
← 返回技术专栏
TECH

零拷贝技术深度解析:从DMA到sendfile的性能优化之道

深入解析DMA技术原理、传统IO的上下文切换开销,以及mmap+write和sendfile两种零拷贝实现方式,助你理解高性能IO的底层优化。

操作系统性能优化

在高性能服务器开发中,文件传输的性能瓶颈往往不在磁盘IO,而在数据拷贝和上下文切换。如何减少这些不必要的开销?零拷贝技术是关键的优化手段。在十三Tech的高性能系统实践中,我们深刻体会到零拷贝带来的巨大收益。本文将从DMA技术出发,剖析传统IO的四次拷贝与四次切换,详解mmap和sendfile两种零拷贝方案,带你掌握高性能IO的核心优化技术。

DMA

直接内存访问(Direct Memory Access

在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务

  • 用户进程调用 read 方法,向操作系统发出 I/O 请求,请求读取数据到自己的内存缓冲区中,进程进入阻塞状态;
  • 操作系统收到请求后,进一步将 I/O 请求发送 DMA,然后让 CPU 执行其他任务;
  • DMA 进一步将 I/O 请求发送给磁盘;
  • 磁盘收到 DMA 的 I/O 请求,把数据从磁盘读取到磁盘控制器的缓冲区中,当磁盘控制器的缓冲区被读满后,向 DMA 发起中断信号,告知自己缓冲区已满;
  • DMA 收到磁盘的信号,将磁盘控制器缓冲区中的数据拷贝到内核缓冲区中,此时不占用 CPU,CPU 可以执行其他任务
  • 当 DMA 读取了足够多的数据,就会发送中断信号给 CPU;
  • CPU 收到 DMA 的信号,知道数据已经准备好,于是将数据从内核拷贝到用户空间,系统调用返回

传统的I/O工作方式

发生了 4 次用户态与内核态的上下文切换

发生了 4 次数据拷贝

要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数

用户的缓冲区是没有必要存在的

零拷贝如何实现

零拷贝技术实现的方式通常有 2 种:

  • mmap + write
  • sendfile

mmap mmap() 系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作

  • 应用进程调用了 mmap() 后,DMA 会把磁盘的数据拷贝到内核的缓冲区里。接着,应用进程跟操作系统内核「共享」这个缓冲区;
  • 应用进程再调用 write(),操作系统直接将内核缓冲区的数据拷贝到 socket 缓冲区中,这一切都发生在内核态,由 CPU 来搬运数据;
  • 最后,把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程是由 DMA 搬运的

sendfile

PageCache

文件传输过程,其中第一步都是先需要先把磁盘文件数据拷贝「内核缓冲区」里,这个「内核缓冲区」实际上是磁盘高速缓存(PageCache

程序运行的时候,具有「局部性」,所以通常,刚被访问的数据在短时间内再次被访问的概率很高,于是我们可以用 PageCache 来缓存最近被访问的数据,当空间不足时淘汰最久未被访问的缓存

读磁盘数据的时候,优先在 PageCache 找,如果数据存在则可以直接返回;如果没有,则从磁盘中读取,然后缓存 PageCache 中。

还有一点,读取磁盘数据的时候,需要找到数据所在的位置,但是对于机械磁盘来说,就是通过磁头旋转到数据所在的扇区,再开始「顺序」读取数据,但是旋转磁头这个物理动作是非常耗时的,为了降低它的影响,PageCache 使用了「预读功能」

PageCache 的优点主要是两个:

  • 缓存最近被访问的数据;
  • 预读功能

总结

零拷贝技术是高性能IO优化的核心手段之一。从DMA解放CPU的数据搬运工作,到mmap减少一次内核到用户态的拷贝,再到sendfile实现真正的内核态零拷贝——每一次优化都在减少不必要的数据移动和上下文切换。配合PageCache的缓存与预读机制,零拷贝能够将文件传输性能推向极致。更多系统性能优化深度内容,敬请关注十三Tech。