当前位置: 首页 > Linux

面试官:Linux零拷贝的原理是什么?

时间:2023-04-06 05:27:39 Linux

1。前言大白这样的switchman就知道,不了解底层技术,就是空中楼阁。再这样下去,阿里p10就没有希望了。想到这里,我开始慌了,所以今天就和大家一起学习一个底层的技术点——Zero-CopyZero-Copy。Linux系统中的一切都是文件。仔细想想,Linux系统中的很多活动无非就是读写操作。零拷贝似乎可以提高读写性能。废话少说,马上开大车,走!在数据拷贝的基本过程中,Linux系统内部的缓存和内存容量是有限的,更多的数据存放在磁盘上。对于web服务器来说,往往需要将数据从磁盘读取到内存,再通过网卡传输给用户:上面的数据流只是一个大框架,下面我们来看几种模式。2.1CPU-only模式当应用程序需要读取磁盘数据时,调用read()从用户态进入内核态,read()系统调用最终由CPU完成;CPU向磁盘发起I/O请求,磁盘收到后开始准备数据;磁盘将数据放入磁盘缓冲区后,向CPU发起I/O中断,报告CPU数据准备好;CPU收到磁盘控制器的I/O中断后,开始复制数据,read()返回,然后从内核态切换到用户态;2.2CPU&DMA模式CPU时间是宝贵的,让它去做杂事是一种资源浪费。直接内存访问(DirectMemoryAccess)是硬件设备绕过CPU,直接独立访问内存的一种机制。因此,DMA在一定程度上解放了CPU,让硬件直接去做之前CPU的杂活,提高了CPU的效率。目前支持DMA的硬件包括:网卡、声卡、显卡、磁盘控制器等。有了DMA的参与,流程发生了一些变化:主要变化是CPU不再直接与磁盘交互,但DMA与磁盘交互,将数据从磁盘缓冲区复制到内核缓冲区,后续过程类似。“【敲黑板】无论是CPU-only模式还是DMA&CPU模式,都存在多重冗余数据副本和内核态与用户态的切换。”我们继续思考web服务器如何读取本地磁盘文件数据,然后通过网络传输给用户的详细过程。3、普通模式数据交互一次完成的数据交互包括几个部分:系统调用syscall、CPU、DMA、网卡、磁盘等。系统调用syscall是应用程序和内核之间的桥梁。每次调用/返回都会导致两次切换:调用syscall从用户态切换到内核态syscall从内核态返回用户态查看完整的数据拷贝过程图:读取数据过程:应用程序需要读取磁盘数据,调用read()函数从用户态切换到内核态,这是第一个状态切换;DMA控制器将数据从磁盘复制到内核缓冲区,这是第一次DMA复制;CPU将数据从内核缓冲区复制到用户缓冲区,这是CPU的第一次复制;CPU完成拷贝后,read()函数返回,从用户态切换到用户态,这是第二次状态切换;写入数据的过程:应用程序需要向网卡写入数据,调用write()函数从用户态切换到内核态,这是第一次切换;CPU将用户缓冲区数据复制到内核缓冲区,这是第一次1CPU复制;DMA控制器将数据从内核缓冲区复制到套接字缓冲区,这是第一次DMA复制;拷贝完成后,write()函数返回实现内核态切换用户态,也就是第二次切换;总结一下:读过程涉及2次空间切换,1次DMA拷贝,1次CPU拷贝;写过程涉及2个空间开关,1个DMA拷贝,1个CPU拷贝;可见,在传统模式下,多次Space切换和数据冗余拷贝效率不高,下一步就是零拷贝技术。零拷贝技术4.1原因我们可以看出,如果应用程序不修改数据,就会从内核缓冲区到用户缓冲区,再从用户缓冲区到内核缓冲区。两次数据拷贝都需要CPU的参与,涉及用户态和内核态的多次切换,增加了CPU的负担。我们要减少冗余的数据拷贝,解放CPU,这就是零拷贝Zero-Copy技术。4.2解决方案目前零拷贝技术的几种实现方式有:mmap+write、sendfile、sendfile+DMAcollection、splice等。4.2.1mmap方式mmap是Linux提供的一种内存映射文件机制,实现映射在内核中读取缓冲区的地址和用户空间中缓冲区的地址之间,从而实现内核缓冲区和用户缓冲区的共享。这样就减少了用户态和内核态的CPU拷贝,但是内核空间还是有CPU拷贝的。mmap对于大文件传输有一定的优势,但是小文件可能会出现碎片,多个进程同时操作文件时可能会产生导致coredump的信号。4.2.2sendfile方法mmap+write方法有一些改进,但是系统调用带来的状态切换并没有减少。sendfile系统调用是Linux内核2.1版本引入的,它在两个文件之间建立传输通道。sendfile方法只用一个函数就完成了前面的read+write和mmap+write函数,省去了两次状态切换。由于数据不经过用户缓冲区,因此无法修改数据。从图中可以看出,应用程序只需要调用sendfile函数就可以完成,而且只有2次状态切换,1次CPU拷贝,2次DMA拷贝。但是内核缓冲区和套接字缓冲区中仍然存在sendfile的CPU副本,也许可以对此进行优化。4.2.3sendfile+DMAcollectionLinux2.4内核优化了sendfile系统调用,但需要硬件DMA控制器的配合。升级后的sendfile将内核空间缓冲区中相应的数据描述信息(文件描述符、地址偏移量等)记录到socket缓冲区中。DMAcontroller根据socketbuffer中的地址和offset,将数据从kernelbuffer中复制到网卡中,这样在kernelspace中只节省了一份CPU拷贝。该方法有2次状态切换,0次CPU拷贝,2次DMA拷贝,但仍然不能修改数据,需要硬件层面DMA的支持,而sendfile只能将文件数据拷贝到socket描述符中。某些限制。4.2.4splice模式splice系统调用是Linux在2.6版本中引入的。不需要硬件支持,不再局限于套接字,实现两个普通文件之间的数据零拷贝。splice系统调用可以在kernelbuffer和socketbuffer之间建立管道传输数据,避免了两者之间的CPU拷贝操作。splice也有一些限制,它的两个文件描述符参数之一必须是管道设备。5、本文小结本文介绍了数据交互的基本过程和传统模型的不足,然后介绍了零拷贝的一些实现方法。零拷贝技术是一种非常底层且重要的读写优化,对提高业务的并发度有很大的帮助。就这样。下次见!最后,如果您觉得这篇文章对您有点帮助,请点个赞。或者可以加入我的开发交流群:1025263163互相学习,我们会有专业的技术解答。如果您觉得这篇文章对您有用,请给我们的开源项目一个小星星:http://github。crmeb.net/u/defu非常感谢!PHP学习手册:https://doc.crmeb.com技术交流论坛:https://q.crmeb.com