零拷贝简单说
1. 零拷贝到底指什么
一般说的零拷贝指的是从用户文件输入到用户文件输出CPU拷贝的次数为零.
要讲零拷贝就要聊一聊和其他的拷贝方式的区别
1.1 两拷贝
上面是自创的名词,是指最原始情况下要完成从用户的存储空间到用户的套接字CPU拷贝的次数为二
代码如下
read(file, tmp_buf, len);
write(socket, tmp_buf, len);
这四次拷贝分别是:
- 磁盘 -> 内核空间(DMA拷贝)
- 内核空间 -> 用户空间(CPU拷贝)
- 用户空间 -> 内核空间(CPU拷贝)
- 内核空间 -> 网卡设备(DMA拷贝)
1.2 一拷贝
一拷贝使用的是mmap() + wirte(),或者sendfile(),将用户空间映射到内核空间
代码如下
// mmap + write
mmap(tmp_buf, len, prot, flags, file_fd, offset);
write(socket, tmp_buf, len);
// sendfile
sendfile(file_fd, socket_fd, offset, len)
这三次拷贝分别是:
- 磁盘 -> 内核空间(DMA拷贝)
- 内核空间 -> 内核空间(CPU拷贝)
- 内核空间 -> 网卡设备(DMA拷贝)
1.3 零拷贝
1.3.1 scatter/gather
DMA分散存储,而后聚集之后传输,避免CPU拷贝
// 需要硬件支持的sendfile
sendfile(file_fd, socket_fd, offset, len)
这两次分别是:
- 磁盘 -> 内核空间(DMA拷贝)
- 内核空间 -> 网卡设备(DMA拷贝)
1.3.2 splice()
与senfile相比,能在任意类型的输出任意类型
splice(file_fd, off_in, socket_fd, off_out, len, flags)
这两次分别是:
- 磁盘 -> 内核空间(DMA拷贝)
- 内核空间 -> 网卡设备(DMA拷贝)
1.3.2 绕过内核
1.3.2.1 用户直接访问硬件
这种技术赋予用户进程直接访问硬件设备的权限,这让用户进程能有直接读写硬件设备,在数据传输过程中只需要内核做一些虚拟内存配置相关的工作
1.3.2.2 内核控制访问硬件
内核会控制 DMA 引擎去替用户进程做缓冲区的数据传输工作
1.3.3 优化用户空间和内核空间数据传输
1.3.3.1 Copy On Write
异步写入
写入的时候才给副本,其他人都读的是一个资源,写的时候写入新的副本,占用了新的空间
1.3.3.2 缓存区共享
用多个内核缓存区代替需要放入用户空间的操作
1.4 现有零拷贝技术
| 使用场景 | 名称 | 系统调用 | 说明 |
|---|---|---|---|
| Linux | sendfile | sendfile | |
| Linux | sendfile64 | sendfile64 | |
| Linux | splice | splice | |
| windows | TransmitFile | TransmitFile | 官方称是零拷贝 |
| Java | FileChannel transferTo | sendfile | |
| 远程直接内存访问(RDMA)协议 | 零拷贝 |
参考资料
https://blog.csdn.net/u013256816/article/details/52589524
https://zhuanlan.zhihu.com/p/308054212
https://zh.wikipedia.org/wiki/%E9%9B%B6%E5%A4%8D%E5%88%B6