操作系统-mmap、sendFile、splice三种零拷贝技术介绍
转载文章
介绍
在传统网络数据传输的过程中,数据会被来回拷贝很多次,而其中有一些是不必要拷贝,而零拷贝技术就是为了减少这些不必要的数据复制操作
。下面会详细介绍各种数据拷贝的详细过程,这也是一个非常高频的面试问题。
传统数据拷贝
当我们通过网络从服务器上获取数据时,数据整体的传输过程是这样子的,如图(可以放大看):
详细过程:
- 等待cpu调度,通过cpu发起io请求,通过read()方法读取数据,此时用户态切换为内核态;
- DMA对硬盘发起IO请求;
- DMA从硬盘中把数据拷贝到pageCache中;
- DMA拷贝完成后发送完成信息;
cpu从pageCache中把数据拷贝到用户缓冲区;
- 此时read()方法调用完成,内核态切换为用户态;
- 等待cpu调度,通过cpu发起io请求,通过write()方法写数据,此时用户态切换为内核态;
cpu把数据从用户缓冲区拷贝到socket缓冲区;
- DMA通知网卡设备要发起IO请求;
- DMA开始进行数据拷贝;
- DMA拷贝完成,通知写完成信息;
- write()方法调用完成,内核态切换为用户态。
上述过程中出现了4次上下文切换,2次cpu拷贝,2次DMA拷贝;可以发现这里面有很多是不必要的操作,如:从pageCache拷贝到用户缓冲区,再从用户缓冲区拷贝到socket缓冲区;而零拷贝的出现就是为了节省这些cpu拷贝、上下文切换,从而提高服务的整体性能。目前linux提供了mmap、sendfile、splice等都是为了省去不必要的操作从而提升服务整体性能。
DMA拷贝
1 |
|
mmap + write
mmap是linux内核提供的一种内存映射文件的方式,将一个进程的虚拟地址映射到磁盘文件地址。它可以将内核缓冲区的地址与用户缓冲区的地址进行映射,从而实现内核缓冲区到用户缓冲区的内存共享。省去数据从内核缓冲区拷贝到用户缓冲区的过程。具体过程如下:
- 发起mmap()调用,建立用户缓冲区和pageCache的地址映射;
- DMA对硬盘发起IO请求;
- DMA从硬盘中把数据拷贝到pageCache中;
- DMA拷贝完成后发送完成信息;
- mmap()调用完成,内核态切换为用户态;
- 等待cpu调度,通过cpu发起io请求,通过write()方法写数据,此时用户态切换为内核态;
cpu把数据从用户缓冲区拷贝到socket缓冲区;
- DMA通知网卡设备要发起IO请求;
- DMA开始进行数据拷贝;
- DMA拷贝完成,通知写完成信息;
- write()方法调用完成,内核态切换为用户态。
后续的write()方法和传统数据拷贝的过程是相同的,整体上发生了4次上下文切换,一次cpu拷贝,节省了一次从pageCache拷贝到用户缓冲区的cpu拷贝过程
;同时用户态空间的共享区使用的是虚拟内存,并不会占用过多的物理内存。
优点:针对大文件可以极大的提高IO性能,但是对于小文件,内存映射反而会导致碎片空间的浪费。
sendfile
sendfile系统调用是Linux2.1引入的目的简化网络通过两个通道之间的数据传输;它可以使数据直接在内核空间进行IO传输,省去了用户空间和内核空间来回拷贝的过程。如图:
- 发起sendfile()调用,用户态切换为内核态;
- DMA对硬盘发起IO请求;
- DMA从硬盘中把数据拷贝到pageCache中;
- DMA拷贝完成后发送完成信息;
cpu从pageCache拷贝到socket缓冲区;
- DMA通知网卡设备要发起IO请求;
- DMA开始进行数据拷贝;
- DMA拷贝完成,通知写完成信息;
- sendfile()调用完成,内核态切换为用户态。
整个过程中只发生了2次上下文切换,1次cpu拷贝;相比mmap+write又节省了2次上下文切换
。 而在linux2.4内核版本开始,又增加了gather操作
,可以把仅有的这次cpu拷贝也省去掉。过程如下:
上图红色字体的过程为改进点。它把数据描述信息读到socket的缓冲区中,DMA Gather Copy根据socket缓冲的数据描述信息批量的从pageCache中读取到网卡设备上。至此剩余的一次pageCache到socket缓冲的cpu拷贝
也被节省掉了。
splice
上面的零拷贝,都是大家平时刷文章经常刷到的,这里再介绍一种不那么常见的splice
。过程图如下:
在第5步是创建一个splice管道,并且把该管道的写端绑定在pageCache上,读端绑定到socket缓冲区上,再通过DMA拷贝到网卡设备上,也实现真正意义上的零cpu拷贝。
作者:想打游戏的程序猿
链接:https://juejin.cn/post/7404036819107102739
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。