零拷贝与应用

114 阅读4分钟

一、传统文件传输过程

Linux传统文件传输过程

image.png

  • 发生了4次用户态与内核态的上下文切换
  • 发生了4次数据拷贝

上下文切换

  • 用户态与内核态
  • 用户空间和内核空间权限不同
  • 数字越小,权限越大
  • 区分用户空间和内核空间的原因:隔离操作系统和应用程序,防止操作系统崩溃。 image.png

CPU拷贝方式

原因:用户态的数据不可信->检查->产生时间窗口->若在窗口期内修改数据则检查无效->需要拷贝进内核空间保证其不变后再检查

I/O轮询

image.png

实现简单,占用CPU全部资源,效率低,时间浪费在等待输入输出的循环检测上。

I/O中断

image.png

一定程度上释放了CPU资源,但是受制于缓冲区的大小,在大数据量传输情况下,CPU会反复中断。

DMA(Direct Memory Access)传输

image.png

简单来说就是加一个中间层,彻底减少了一次CPU拷贝,但是依赖设备硬件支持。

二、零拷贝的实现方式

定义

零拷贝不是0次拷贝数据,而是减少CPU拷贝次数,减少上下文切换次数。

方案一:mmap(memory map)+write

image.png

mmap本质上是一种进程虚拟内存映射的方法,可以将一个文件或者一段物理内存映射到进程的虚拟内存地址空间,进程可以用指针的方式来读取,不必调用read函数,减少了一次数据拷贝。

方案二:sendfile

image.png

发生在内核空间中,减少了两次上下文切换的时间。

方案三:sendfile+gather

image.png

需要有gatherdma功能,将关于数据的位置和长度等信息de的描述符传递到socket缓冲区中,之后再由dma引擎直接拷贝到设备中。

方案三:splice

image.png 通过管道进行数据传输

所有拷贝实现方式的对比

image.png

三、Go语言中的实现

mmap+write的使用

image.png

在内核中分出一部分内存,实际映射到磁盘文件上,根据标识决定是可读,可写的。

io.Copy方法

image.png

调用copyBuffer方法,在TCPconnection中实现其readfrom方法,其中的优先级是splice最高,sendFile其次,最后是readFrom,所以splice是更通用的。

四、零拷贝的应用

Kafka

image.png

image.png

  • 运用了mmap方法:首先建立一个稀疏索引,利用mmap进行稀疏索引文件的读写。

  • 运用了sendfile方法:consumer不需要对数据进行修改,可以采用零拷贝方式,节省cpu拷贝次数和上下文切换次数

RocketMQ

image.png

  • 通过mmap+write实现,满足小数据需求
  • 通过文件预热的方式解决缺页的问题

总结

零拷贝(Zero-copy)是一种高效的数据传输机制,在追求低延迟的传输场景中十分常用。它通过减少CPU消耗和内存带宽占用,减少用户空间与CPU内核空间的拷贝过程,减少用户上下文与CPU内核上下文间的切换,提高系统效率。

零拷贝技术通常用于网络文件传输,它可以通过几种不同的实现手段,包括mmap+write、sendfile、sendfile+DMA收集、splice等。这些技术都旨在降低冗余数据拷贝、解放CPU,提高读写性能。在网络传输中,数据通常需要经过多次拷贝才能从源头到达目的地。例如,在传统的网络文件传输中,数据需要从磁盘读取到内核缓冲区,然后从内核缓冲区拷贝到用户缓冲区,再从用户缓冲区拷贝到套接字缓冲区,最后从套接字缓冲区发送到网络。这样的过程中,数据被多次拷贝,消耗了大量的CPU时间和内存带宽。

零拷贝技术通过优化数据传输路径,减少了数据拷贝的次数。例如,使用mmap+write技术时,数据可以直接从磁盘读取到用户缓冲区,然后通过write系统调用直接写入套接字缓冲区,省去了内核缓冲区的拷贝过程。使用sendfile技术时,数据甚至可以直接从磁盘读取到套接字缓冲区,完全避免了用户空间的拷贝。

零拷贝技术不仅可以提高网络文件传输的效率,还可以用于其他场景。例如,在数据库系统中,零拷贝技术可以用于优化磁盘读写性能;在虚拟化环境中,零拷贝技术可以用于优化虚拟机之间的数据传输。

因此,零拷贝技术是非常底层且重要的读写优化,对于服务并发能力的提升有很大帮助。我认为这是一个非常重要且有趣的技术领域,值得进一步研究和探索。