首页 > 编程知识 正文

零拷贝网卡(零拷贝技术)

时间:2023-05-06 08:48:37 阅读:90179 作者:1226

传统的文件传输有什么缺点?

传统的IO机制从用户空间和内核空间读取和写入数据,而内核空间中的数据通过操作系统级IO接口从磁盘读取和写入。

如上图所示,在运行read和writer时,总共发生了四次用户状态和内核状态上下文切换。 在高并发性场景中,用户状态和内核状态上下文切换引起的性能消耗会大幅降低系统性能。

除了上下文切换外,此过程还发生了4次数据拷贝,包括2次DMA拷贝和2次CPU拷贝。

第一次复制:用DMA完成,将磁盘上的数据复制到内核缓冲区第二次复制:用CPU完成,将内核缓冲区的数据复制到用户缓冲区,以便APP应用程序可以操作这些数据的第三次复制要将用户缓冲区中的数据复制到内核中套接字的缓冲区,需要由CPU完成第四次复制。 要在DMA中完成,如果将内核套接字缓冲区中的数据复制到网卡缓冲区,则在尝试通过网络发送作为一个主机的文件的内容时,将进行四次切换和四次复制,但在这四次复制之间

因此,为了优化文件的传输性能,需要减少上下切换和复制的次数。

如何实现零拷贝?

映射写入顺序文件映射写入

read (系统调用将内核缓冲区的内容复制到用户空间。 为了减少这次的拷贝,将read )替换为mmap )系统调用

由于map函数直接将内核缓冲区中的数据映射到用户空间,因此操作系统内核和用户空间不需要复制数据。

当应用进程调用mmap函数时,DMA将磁盘数据复制到内核缓冲区,APP与操作系统内核共享该缓冲区应用进程,然后调用write函数,操作系统调用内核日在此步骤中,必须使用CPU最后使用DMA将套接字缓冲区中的数据复制到网卡缓冲区

mmap write的实现需要3次数据拷贝和4次上下文切换

发送文件

sendfile是一个系统调用函数,专门用于在Linux内核版本2.1中发送文件,函数格式如下:

# #包括系统/套接字. h

size _ t sendfile (输入输出,输入输出,关闭偏移,大小计数);

out_fd :目标文件描述符in_fd :源文件描述符offset :源侧的偏移量count :复制数据的长度ssize_t :返回参数,实际复制的数据的长度(9502.163 . )

sendfile可以代替read () ()和write ) )的两个系统调用,因此系统调用将是两次到一次,上下文切换也相应地是两次。

其次,由于sendfile可以将内核缓存器的数据直接复制到套接字缓存器,所以通过sendfile函数,可以将上下文切换减少到2次,将数据复制减少到3次。

如何实现真正的零拷贝?

上述零拷贝还不是真正的零拷贝。 如果网卡支持SG-DMA技术,则可以进一步减少数据复制的次数。 这意味着可以减少CPU将内核缓冲区的内容复制到套接字缓冲区的过程。

$ ethtool-keth0| grep scatter-gather

通过上述命令,可以确认网卡是否支持SG-DMA

技术。

在Linux内核2.4y以后,对于网卡支持SG-DMA技术的情况下,sendfile系统调用的过程也发生了变化:

首先通过DMA拷贝将磁盘的数据拷贝到内核缓冲区第二步,将缓冲区描述符和数据长度传到Socket缓冲区,网卡的SG-DMA控制器可以直接将内核缓冲区的数据拷贝到网卡的缓冲区里

通过以上技术,我们真正实现了零拷贝,数据拷贝次数发生两次,并且我们全程没有让CPU介入数据拷贝过程,通过DMA技术实现了数据的拷贝。总体来看,零拷贝技术可以把文件性能至少提高一倍以上。

PageCache是什么?

在我们上面一直提到一个内核缓冲区,该内核缓冲区就是PageCache(磁盘高速缓存)。

PageCache的优点?

PageCache存在于内存中,读写内存速度远远快于读写磁盘速度根据程序局部性规则,刚刚访问的数据在短时间内被访问的概率很高,因此PageCache缓存了最近被访问的数据,当读磁盘数据时,优先在PageCache中查找,如果数据存在可以直接返回,如果没有就需要从磁盘中读取,当空间不足时需要淘汰最久未被访问的缓存PageCache使用了预读功能,比如read方法每次只读取32kb,但内核实际上会将后面的32kb-64kb的内容也读取到PageCache,这样对于读取后续的数据成本就会变低

PageCache的缺点?

不适合传输大文件(GB级别),在传输大文件时,PageCache会失效,也就是说DMA的数据拷贝是一次多余的操作。PageCache如果长时间被大文件占据,热点的小文件就无法使用到PageCache

所以针对大文件的传输,不应该使用零拷贝技术。

如何解决大文件传输问题?

异步IO + 直接IO。

异步IO主要解决read方法调用时的阻塞问题,通过上图可以看出:

在内核向磁盘发起读请求时,可以不等待数据就位就可以返回,此时进程依旧可以处理其他任务当磁盘中的数据拷贝到用户缓冲区时,进程将收到内核的通知,此时进程就可以去处理数据了

异步IO整个过程没有涉及到PageCache,绕开PageCache的IO也可以成为直接IO。通常对于磁盘来说,异步IO只支持直接IO。

所以在传输大文件时,可以使用异步IO+直接IO无阻塞的读取文件。

直接IO的使用场景?

应用程序已经实现了磁盘数据的缓存,那么便不再需要PageCache了。在MySQL数据库中,可以通过参数开启直接IO传输大文件时,由于大文件无法命中PageCache缓存,因此也应该使用直接IO

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。