传统的IO模型
如果要把磁盘中的某个文件发送到远程服务器需要经历以下几个步骤
(1) 从磁盘中读取文件的内容,然后拷贝到内核缓冲区
(2) CPU把内核缓冲区的数据赋值到用户空间的缓冲区
(3) 在用户程序中调用write方法,把用户缓冲区的数据拷贝到内核下面的Socket Buffer中
(4) 把内核下面的Socket Buffer中的数据赋值到网卡的缓冲区
(5) 网卡的缓冲区把数据传输到目标服务器上
我们可以看到这个过程中经历了四次拷贝
我们所说的零拷贝并不是没有拷贝(数据赋值),去掉的两次浪费的拷贝分别是
1.从内核空间赋值到用户空间的拷贝
2.从用户空间再次复制到内核空间的拷贝
由于用户空间和内核空间的切换会带来CPU的上下文切换,对于CPU的性能也会造成影响
零拷贝就是把这两次多余的拷贝省略掉,应用程序可以直接把磁盘中的数据从内核中直接传输给Socket,而不再需要经过应用程序所在的用户空间,所以零拷贝不是没有拷贝,而是对于用户空间来说,不再需要进行数据拷贝,这只是较少了不必要的拷贝次数而已
零拷贝的原理
在程序中实现零拷贝的方式:
-
在Linux中,零拷贝技术依赖于底层的sendfile方法实现
-
在Java中,FileChannel.transferTo()方法的底层调用就是sendfile方法
-
MMAP文件映射机制
mmap(即 memory-mapped file)是一种内存映射文件的机制,它可以让程序将一个文件映射到进程的地址空间,从而实现文件和内存的无缝转换。
具体来说,使用mmap将一个文件映射到进程的地址空间后,该文件就可以像普通的内存一样被读写,甚至可以在多个进程之间共享,而不需要进行繁琐的文件读写操作。在使用mmap时,操作系统会自动将文件的某些部分或者整个文件的内容映射到内存中,而这些映射的内存区域可以被当作普通的内存指针来访问,从而实现对文件内容的访问。
mmap的一些主要应用场景包括:
实现零拷贝(zero-copy)网络传输:可以将网络数据直接映射到进程的地址空间,避免了数据拷贝的开销。
实现高性能的数据库和搜索引擎:将大规模的数据文件映射到内存中,可以大大提升数据的访问速度。
实现内存共享和进程间通信:多个进程可以映射同一个文件到它们各自的地址空间,从而实现进程间共享数据的目的。
版权声明:本文为CSDN博主「鱼跃鹰飞」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Chang_Yafei/article/details/129505855
Kafka采用sendfile的方式去完成拷贝的过程