客户端需要访问服务器上的文件资源,传统的文件传输性能表现会很糟糕。过程如下:
1.服务端将磁盘上的文件读取出来
2.然后通过网络发送给客户端。
传统I/O的工作方式是,数据读取和写入是从用户空间到内核空间来回复制,而内核空间的数据是通过操作系统的I/O接口从磁盘读取或写入。一般涉及到两个系统调用:
read(file, tmp_buf, len);
write(socket, tmp_buf, len);
如图:
消耗性能的环节:
- 用户态与内核态上下文切换
无论是read操作还是write操作,每次操作都会发生 用户态到内核态的切换 和 内核态到用户态的切换。
- 数据拷备
- DMA控制器将数据从磁盘拷备到内核缓冲区
- CPU将数据从内核缓冲区拷备到用户空间的缓冲区
- CPU将数据从用户空间的缓冲区拷备到内核空间的socket缓冲区
- DMA控制器将数据从内核空间的socket缓冲区拷备到网卡
传统方式中的数据拷备过程有很大的优化空间。这种方式在高并发场景里表现会非常糟糕。
零拷备技术实现方式通常有两种:
- mmap
mmap 系统调用函数会将内核缓冲区里的数据映射到用户空间,这样就省去了CPU拷备的开销。
- sendfile
可以替代 read()和write()两个系统调用,直接完成内核缓冲区到socket缓冲区的数据拷备
如果网卡支持 SG_DMA技术,可以直接通过如下图所示的方式来完成数据的拷备:
这样,所有数据的拷备全程没有CPU的参与 ,这就是所谓的零拷备。