高频面试题:什么是零拷贝?在哪些地方使用了?( 二 )


(3)FileChannel
FileChannel 定义了 transferFrom() 和 transferTo() 两个抽象方法,它通过在通道和通道之间建立连接实现数据传输的 。
我们直接看Linux2.4的版本,socket缓冲区做了调整,DMA带收集功能 。
(1)DMA从拷贝至内核缓冲区
(2)将数据的位置和长度的信息的描述符增加至内核空间(socket缓冲区)
(3)DMA将数据从内核拷贝至协议引擎
这个复制过程是零拷贝过程 。
2、Netty
Netty 中的零拷贝和上面提到的操作系统层面上的零拷贝不太一样, 我们所说的 Netty 零拷贝完全是基于(Java 层面)用户态的 。
(1)Netty 通过 DefaultFileRegion 类对FileChannel 的 tranferTo() 方法进行包装,相当于是间接的通过java进行零拷贝 。
(2)我们的数据传输一般都是通过TCP/IP协议实现的,在实际应用中,很有可能一条完整的消息被分割为多个数据包进行网络传输,而单个的数据包对你而言是没有意义的,只有当这些数据包组成一条完整的消息时你才能做出正确的处理,而Netty可以通过零拷贝的方式将这些数据包组合成一条完整的消息供你来使用 。
此时零拷贝的作用范围仅在用户空间中 。那Netty是如何实现的呢?为此我们就要找到Netty进行数据传输的接口,这个接口一定包含了可以实现零拷贝的功能,这个接口就是ChannelBuffer 。
既然有接口肯定就有实现类,一个最主要的实现类是CompositeChannelBuffer,这个类的主要作用是将多个ChannelBuffer组成一个虚拟的ChannelBuffer来进行操作
为什么说是虚拟的呢,因为CompositeChannelBuffer并没有将多个ChannelBuffer真正的组合起来,而只是保存了他们的引用,这样就避免了数据的拷贝,实现了Zero Copy 。
【高频面试题:什么是零拷贝?在哪些地方使用了?】(3)ByteBuf 可以通过 wrap 操作把字节数组、ByteBuf、ByteBuffer 包装成一个 ByteBuf 对象, 进而避免了拷贝操作
(4)ByteBuf 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf,避免了内存的拷贝
3、kafka
Kafka 的索引文件使用的是 mmap + write 方式,数据文件使用的是 sendfile 方式 。适用于系统日志消息这种高吞吐量的大块文件的数据持久化和传输 。
如果有10个消费者,传统方式下,数据复制次数为4*10=40次,而使用“零拷贝技术”只需要1+10=11次,一次为从磁盘复制到页面缓存,10次表示10个消费者各自读取一次页面缓存 。
OK,先到这里 。




推荐阅读