什么是零拷贝呢? 这个词想必听过不止一次了吧, 但一直没有认真的研究一下这到底是个什么玩意.
在很久之前, 一次IO 操作的流程大致是这样的:
read
read
在上面的数据获取的过程中, 发生了3次数据的拷贝, 其中2次是 CPU 全程参与的. 而这个过程, CPU 忙于拷贝数据, 无暇做其他工作.
DMA
DMA
readDMADMADMADMAread
于是, 一次数据读取的流程变成了这样:
现在, 每一次的数据读取, 都会发生2次数据拷贝(IO设备内部的就不算在其中了). 而零拷贝就是为了解决这个问题.
解决方案mmap
想一下, 为什么数据需要从内核缓冲区拷贝到应用缓冲区? 他们用的明明是同一个物理内存呀. 还不是因为虚拟内存的存在, 所以他们在内存空间的不同地址. 如果能够让他俩共用用一段物理内存, 不就不需要拷贝数据了.
mmap
Gommap
package main
import (
"fmt"
"golang.org/x/exp/mmap"
)
func main() {
at, _ := mmap.Open("./tmp.txt")
buff := make([]byte, 1024)
_, _ = at.ReadAt(buff, 0)
_ = at.Close()
fmt.Println(string(buff))
}
write
mmapDMSDMS
mmap
sendfile
我们知道, 应用程序调用系统是需要进行上下文切换的, 是否有一个函数直接告诉 CPU 把2个 IO 设备的数据进行拷贝? 这样就可以减少一次系统调用嘛.
sendfile
Gosyscall.Sendfile
你以为这就完了么? 不, 这还不是零拷贝, 这此种仍然存在一次 CPU 主导的内存拷贝.
零拷贝
mmap
DMA
ethtool -k eth0 | grep scatter-gather
CPU
sendfile
总结
kafka
如何, 简单看下来, 零拷贝也没有那么什么嘛. 此项暂时搁置, 再见