【Netty】mmap 和 sendFile 零拷贝原理(一)

简介: 【Netty】mmap 和 sendFile 零拷贝原理(一)

一、 零拷贝 简介


零拷贝作用 : 在网络编程中 , 如果要进行性能优化 , 肯定要涉及到零拷贝 , 使用零拷贝能极大的提升数据传输性能 ;



零拷贝类型 : mmap ( 内存映射 ) 和 sendFile;



数据角度分析 : 在零拷贝机制中 , 整个数据在内存中只有一份数据 , 非零拷贝机制中 , 内核缓冲区 , 用户缓冲区 , Socket 缓冲区 , 各有一份数据 ;



零拷贝指的是没有 CPU 拷贝 , 都是 DMA ( 直接内存访问 ) 拷贝 ;



零拷贝性能优势 : 没有复制数据带来的内存开销 , 没有 CPU 拷贝 , 直接节省了大量 CPU 计算资源 ;






二、 传统 BIO 数据拷贝分析 ( 4拷贝 4切换 )


传统 BIO 数据拷贝代码示例 :


package kim.hsl.nio.zerocopy;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
public class BIOClientDemo {
    public static void main(String[] args) {
        try {
            // 客户端与服务器端连接过程忽略, 主要是分析数据拷贝过程
            Socket socket = new Socket();
            InetSocketAddress inetSocketAddress =
                    new InetSocketAddress(Inet4Address.getLocalHost(), 8888);
            socket.connect(inetSocketAddress);
            // 分析下面过程中, 数据拷贝次数, 和用户态与内核态的转换次数
            // 1. 从文件中读取数据
            FileInputStream fileInputStream = new FileInputStream("file.txt");
            byte[] buffer = new byte[1024];
            // 首先将硬盘中的文件, 进行 DMA 拷贝, 此处对应 read 方法, 
            // 将文件数据从硬盘中拷贝到 内核缓冲区  ( 用户态切换成内核态 )
            // 将内核缓冲区中的数据, 通过 CPU 拷贝 方式, 拷贝到 用户缓冲区  ( 内核态切换成用户态 )
            int readLen = fileInputStream.read(buffer);
            // 2. 写出数据到服务器
            // 将用户缓冲区中的数据, 再次通过 CPU 拷贝方式, 拷贝到 Socket 缓冲区 ( 用户态切换成内核态 )
            // 再次使用 DMA 拷贝, 将 Socket 缓冲区中的数据拷贝到 协议栈 ( Protocol Engine ) 中
            socket.getOutputStream().write(buffer, 0, readLen);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}



分析上述代码中数据拷贝次数 , 用户态与内核态状态切换 ;




1 . fileInputStream.read(buffer) 操作数据拷贝及状态转换分析 :



① 硬盘 ( 初始用户态 ) -> 内核缓冲区 ( 内核态 ) : 首先将硬盘中的文件 , 进行 DMA[ 1 ] ^{[1]}

[1]

 拷贝 , 此处对应 read 方法 , 将文件数据从硬盘中拷贝到 内核缓冲区 ; ( 用户态切换成内核态 )



② 内核缓冲区 ( 内核态 ) -> 用户缓冲区 ( 用户态 ) : 将内核缓冲区中的数据 , 通过 CPU 拷贝 方式 , 拷贝到 用户缓冲区 ; ( 内核态切换成用户态 )




2 . socket.getOutputStream().write(buffer, 0, readLen) 操作数据拷贝及状态转换分析 :



① 用户缓冲区 ( 用户态 ) -> Socket 缓冲区 ( 内核态 ) : 将用户缓冲区中的数据 , 再次通过 CPU 拷贝 方式 , 拷贝到 Socket 缓冲区 ; ( 用户态切换成内核态 )



② Socket 缓冲区 ( 内核态 ) -> 协议栈 : 再次使用 DMA[ 1 ] ^{[1]}

[1]

 拷贝 , 将 Socket 缓冲区中的数据拷贝到 协议栈 ( Protocol Engine ) 中 ;




3 . 总结 : 上述进行了 4 44 次拷贝 , 3 33 次用户态与内核态之间的状态切换 , 代价很高 ;



① 拷贝次数分析 : 开始时数据存储在 硬盘文件 中 , 直接内存拷贝 ( Direct Memory Access ) 到 内核缓冲区 , CPU 拷贝 到 用户缓冲区 , CPU 拷贝 到 Socket 缓冲区 , 直接内存拷贝 ( Direct Memory Access ) 到 协议栈 ;



硬盘文件 -> 内核缓冲区 ( 内核空间 ) -> 用户缓冲区 ( 用户空间 ) -> Socket 缓冲区 ( 内核空间 ) -> 协议栈



② 状态改变分析 : 开始运行的是用户应用程序 , 起始状态肯定是用户态 , 之后将硬盘文件数据拷贝到内核缓冲区后 , 转为内核态 , 之后又拷贝到了用户缓冲区 , 转为用户态 ; 数据写出到 Socket 缓冲区 , 又转为内核态 , 最后再切换成用户态 , 执行后续应用程序代码逻辑 ;



用户态 -> 内核态 -> 用户态 -> 内核态 -> 用户态




[ 1 ] [1][1] DMA 全称 ( Direct Memory Access ) , 直接内存拷贝 , 该拷贝通过内存完成 , 不涉及 CPU 参与 ;


目录
相关文章
|
7月前
|
网络协议
【Netty 网络通信】Socket 通信原理
【1月更文挑战第9天】【Netty 网络通信】Socket 通信原理
|
缓存 安全 Java
由浅入深Netty基础知识NIO三大组件原理实战 2
由浅入深Netty基础知识NIO三大组件原理实战
82 0
|
Java
由浅入深Netty基础知识NIO三大组件原理实战 1
由浅入深Netty基础知识NIO三大组件原理实战
103 0
|
7月前
|
Java Unix Linux
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
当涉及到网络通信和高性能的Java应用程序时,Netty是一个强大的框架。它提供了许多功能和组件,其中之一是JNI传输。JNI传输是Netty的一个特性,它为特定平台提供了高效的网络传输。 在本文中,我们将深入探讨Netty提供的特定平台的JNI传输功能,分析其优势和适用场景。我们将介绍每个特定平台的JNI传输,并讨论其性能、可靠性和可扩展性。通过了解这些特定平台的JNI传输,您将能够更好地选择和配置适合您应用程序需求的网络传输方式,以实现最佳的性能和可靠性。
149 7
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
|
4月前
|
Java 调度
Netty运行原理问题之ChannelHandler在Netty中扮演什么角色
Netty运行原理问题之ChannelHandler在Netty中扮演什么角色
|
4月前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
4月前
|
编解码 网络协议 开发者
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
|
4月前
|
调度
Netty运行原理问题之事件调度工作的问题如何解决
Netty运行原理问题之事件调度工作的问题如何解决
|
1月前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
4月前
|
开发者
Netty运行原理问题之Netty高性能实现的问题如何解决
Netty运行原理问题之Netty高性能实现的问题如何解决