使用缓存I/O发送数据到网络
首先看一下使用缓存I/O从磁盘文件读取数据并发送到网络上的过程:
文章插图
- 用户发起系统调用,进入到内核态,DMA从磁盘上读取数据到内核缓冲区(DMA复制);
- CPU将内核缓冲区的数据拷贝到用户缓冲区(CPU复制),切换回到用户空间;
- 再次从用户空间切换到内核空间,CPU将用户缓冲区的数据拷贝到socket缓冲区(CPU复制);
- DMA将socket缓冲区的数据拷贝到网卡(DMA复制),之后从内核空间切换回用户空间;
Linux中的零拷贝sendfileLinux在2.1版本中引入了sendfile函数,可以实现将数据从一个文件描述符传输到另外一个文件描述符:
- 发起sendfile系统调用,进入到内核空间;
- DMA从磁盘读取文件到内核缓冲区(DMA复制);
- 将内核缓冲区数据拷贝到socket缓冲区(CPU复制);
- 将socket缓冲区数据拷贝到网卡(DMA复制),之后切换回用户空间;
文章插图
sendfile + DMA GATHERLinux在2.4版本中引入了gather技术,我们知道内核缓冲区在内存中有对应的地址,gather操作可以将内核缓冲区的内存地址、地址偏移量信息记录到socket缓冲区中,之后DMA根据地址信息从内存中读取数据到网卡中 , 减少了数据从内核缓冲区到socket缓冲区的拷贝过程:
文章插图
可以看到零拷贝并不是指的数据一次拷贝都没有发生,而是指减少CPU进行数据拷贝的次数 。
Java中的零拷贝MappedByteBuffer在内存映射中说过,可以通过文件映射的方式将磁盘的文件内容映射到虚拟地址空间,用户空间就可以通过虚拟地址直接访问物理内存中的映射的文件数据,而Java NIO中也提供了
MappedByteBuffer
来处理文件映射,使用MappedByteBuffer
向网络中发送数据的过程如下:- 使用MappedByteBuffer建立文件映射 , 用户空间可以通过虚拟地址直接访问映射的文件数据;
- 将映射的文件数据拷贝到socket网络缓冲区(CPU复制);
- DMA将socket缓冲区的数据拷贝到网卡(DMA复制);
文章插图
MappedByteBuffer减少了从内核缓冲区到用户缓冲区的数据拷贝 , 可以直接将内核缓冲区的数据拷贝到网络缓冲区 。
FileChannelJava NIO中的FileChannel可以实现将数据从FileChannel直接传输到另一个Channel,它是sendfile的一种实现:
RandomAccessFile file = new RandomAccessFile(new File("/Users/sml/test.txt"), "r");// 获取FileChannelFileChannel fileChannel = file.getChannel();long size = fileChannel.size();SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 8080));fileChannel.transferTo(0,size,socketChannel);
参考【极客时间-倪朋飞】Linux性能优化实战
【极客时间-刘超】趣谈Linux操作系统
【拉勾教育-若地】Netty 核心原理剖析与 RPC 实践
【 Kirito的技术分享】文件IO操作的最佳实践
【小码农叔叔】java使用nio读写文件
【占小狼】深入浅出MappedByteBuffer
【零壹技术栈】深入剖析Linux IO原理和几种零拷贝机制的实现
【tomas家的小拨浪鼓】堆外内存 之 DirectByteBuffer 详解
网络IO和磁盘IO详解
推荐阅读
- 玩绝地求生,怎样快速上分(pubg快速上分)
- 一篇文章让你搞懂Java中的静态代理和动态代理
- 不允许还有Java程序员不了解BlockingQueue阻塞队列的实现原理
- 火影忍者10月11日微信每日一题答案是什么
- 4 Java注解:一个真实的Elasticsearch案例
- 【C++】spdlog光速入门,C++logger最简单最快的库
- 无期迷途疑凶追影娜恰打法是什么
- 支付宝蚂蚁庄园10月13日正确答案是什么
- 火影忍者10月12日微信每日一题答案是什么
- 【python】Ubuntu中多条命令的运行