『面试问答』:什么是零拷贝?
面试官 : 请说一下,什么是零拷贝?
零拷贝是指计算机执行IO操作时,CPU不需要将数据从一个存储区域复制到另一个存储区域,从而减少上下文切换以及数据拷贝的时间。零拷贝是一种IO操作优化技术,它并不是真的没有数据拷贝,而是广义上讲的减少和避免不必要的数据拷贝。
以读取一个文件并通过socket发送文件数据为例,一般需要read和write两个系统调用:
这种传统的IO读写流程,需要4次用户态和内核态的上下文切换和4次数据拷贝,这些额外的上下文切换和数据拷贝,会消耗大量的CPU资源和内存带宽,降低数据传输的效率。
零拷贝减少了上下文切换和内存拷贝的次数,主要实现方式有四种:
1 mmap
read系统调用会把内核缓冲区的数据拷贝到用户缓冲区里,为了减少这一开销,我们可以用 mmap 替换 read 。mmap直接把内核缓冲区里的数据映射到用户空间,这样内核与用户空间就不需要再进行任何的数据拷贝操作。
mmap+write方式发生了四次上下文切换以及三次数据拷贝,相对传统的IO方式,减少了一次CPU数据拷贝。
2 sendfile
sendfile是一个专门发送文件的系统调用函数,适用于将数据从文件拷贝到 socket 套接字上,使用sendfile需要硬件的支持。
通过sendfile传输文件,只需要两次上下文切换和两次DMA数据拷贝,相对传统的IO方式,sendfile去除了CPU拷贝,提升了系统性能。
3、splice
splice不需要硬件支持,可以在内核空间的读缓冲区和网络缓冲区之间建立管道,从而避免了两者之间的 CPU 拷贝操作。splice可以用于源文件描述符和目的文件描述符都是socket的情况。splice使用了 Linux 的管道缓冲机制,可以在任意两个文件描述符间传输数据,但是两个文件描述符中必须有一个是管道。
4、tee
tee与splice类似,但两个文件描述符都必须是管道。tee是两个描述符之间进行数据复制,不会消耗数据,因此源文件描述符上的数据仍然可以用于后续的读操作。
在很多开源项目中,比如Kafka 、 Nginx、RocketMQ等, 都有使用零拷贝技术。
分享软件开发岗位面试题及答案

