传统文件的传输过程
一共是四次上下文切换和四次拷贝,极大的占用了CPU的运行时间。
什么是零拷贝
零拷贝不是0次拷贝,而是为了减少上下文切换和CPU的拷贝次数。 最原始的就是read()和write(),会占用CPU大量的时间在拷贝文件上,也会造成大量的上下文切换。 原来 8 张图,就可以搞懂「零拷贝」了 随着Linux系统的发展,系统调用的不断更新,使得零拷贝技术成为可能。
上面是一张总结表,可见splice和sendfile+gather DMA(硬件支持)系统调用可以达成最好的零拷贝,但是用户进程是不可以修改数据的。
DMA
通过DMA实现了数据的批量拷贝,在DMA之前通过轮询和中断的方式会产生大量的系统调用。不过DMA需要硬件的支持。
mmap+write
通过开辟一块用户空间和内核空间的一块共享内存,减少一次CPU拷贝。
sendfile
sendfile表示在两个文件描述符之间传输数据,它是在操作系统内核中操作的,避免了数据从内核缓冲区和用户缓冲区之间的拷贝操作,也减少了上下文切换。
通过 gatter DMA,通过对于内存缓存区取描述符+偏移长度传到 socket 缓冲区,这样网卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里了,实现了CPU的零次拷贝。
splice
比sendfile颗粒度更高,使用
splice() 发送文件时,并不需要将文件内容读取到用户态缓存中,但需要使用管道作为中转。管道只是作为一个通道,并不会产生数据拷贝。
总结
零拷贝技术对于实现高性能的IO十分重要,kafka和RocketMQ正是在是否能在用户空间读取数据,和有序等实现上,采用了不同的零拷贝技术。我还没有实际使用过消息队列,使用过后应该会有更大的感触。