零拷贝

 

所谓零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在IO读写过程中。

目前市面上大部分的高性能软件,比如Nginx、Kafka等等,都有零拷贝的身影。

我们通过一个传统IO读取文件,然后通过网络发送的例子来入手,详情看下图:

 

由上图可知,在一个简单的文件读取发送的过程中,会经历四次文件拷贝:

* 第一次:将磁盘文件,读取到操作系统内核缓冲区
* 第二次:将内核缓冲区的数据,copy到application应用程序的buffer
* 第三步:将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区)
* 第四次:将socket buffer的数据,copy到网络协议栈,由网卡进行网络传输

除此之外,实际的IO读写,需要进行IO中断,需要CPU响应中断(内核态到用户态转换),尽管引入DMA(Direct Memory
Access,直接存储器访问)来接管CPU的中断请求,但四次copy的过程中,第二个和第三个数据副本的拷贝是不需要的。数据可以直接从读缓冲区传输到套接字缓冲区。

所以,所谓的零拷贝,就是磁盘文件通过网络发送。磁盘数据通过DMA(Direct Memory
Access,直接存储器访问)拷贝到内核态Buffer。之后不经过用户态,而是直接从内核态将数据拷贝到NIO Buffer(socket buffer)。

零拷贝是需要底层的操作系统支持的,我们以Linux为例,Linux **2.4+** 内核通过`sendfile`
系统调用,提供了零拷贝。除了减少数据拷贝外,Linux整个读文件 ==> 网络发送由一个`sendfile`调用完成,整个过程只有两次上下文切换,因此大大提高了性能。

Java NIO对`sendfile`的支持就是`FileChannel.transferTo()/transferFrom()。

 

posted on 2023-07-17 13:59  中二的火系魔法师  阅读(18)  评论(0编辑  收藏  举报

导航