io.netty学习(九)Netty 如何实现零拷贝

news2024/10/6 4:09:47

目录

前言

Java 实现零拷贝

1、Java提供 mmap/write 方式

2、Java 提供 sendfile 方式

Netty 实现零拷贝

1、CompositeByteBuf 方式

2、wrap 方式

3、slice 方式

4、 FileRegion 方式

总结


前言

本篇文章我们就来讲讲 Netty 的零拷贝,在这之前,我们先来了解一下 Java 是怎么实现零拷贝的。

io.netty学习使用汇总 

Java 实现零拷贝

Java 实现零拷贝是基于底层操作系统的。就目前而言,Java 支持两种零拷贝技术:mmap/write方式及sendfile方式。

1、Java提供 mmap/write 方式

Java NIO 提供的MappedByteBuffer,用于提供mmap/write方式。

Java NlO 中 的Channel (通道)就相当于操作系统中的内核缓冲区,有可能是读缓冲区,也有可能是网络缓冲区,而Buffer就相当于操作系统中的用户缓冲区。

以下是一个MappedByteBuffer的使用案例:

File file = new File("jw.txt");
try {
    FileChannel fc = new RandomAccessFile(file, "rw").getChannel();
    MappedByteBuffer map = fc.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
    map.put("jiangwang".getBytes());
    fc.position(file.length());
    map.clear();
    fc.write(map);
} catch (IOException e) {
    e.printStackTrace();
}

上述示例中,通过FileChannel.map()方法来创建MappedByteBuffer,该方法底层就是调用Linux的 mmap()实现的。

该方法将内核缓冲区的内存和用户缓冲区的内存做了一个地址映射。这种方式适合读取大文件,同时也能对文件内容进行更改,但是如果其后要通过SocketChannel发送,还是需要CPU进行数据的拷贝。

使用MappedByteBuffer,如果是小文件,执行效率不高;而且MappedByteBuffer只能通过调用FileChannelmap()取得,再没有其他方式。因此,Java 中设计MappedByteBuffer就是为大文件准备的。

2、Java 提供 sendfile 方式

Java FileChannel.transferTo() 底层实现就是通过 Linux 的 sendfile实现的。该方法直接将当前通道内容传输到另一个通道,没有涉及Buffer的任何操作。

以下是FileChannel.transferTo() 的使用示例:

//使用sendfile:读取磁盘文件,并网络发送
FileChannel sourceChannel = new RandomAccessFile(source, "rw").getChannel();
SocketChannel socketChannel = SocketChannel.open(sa);
sourceChannel.transferTo(0, sourceChannel.size(), socketChannel);

Netty 实现零拷贝

Netty 中的零拷贝的实现是基于 Java 的,换言之,底层也是基于操作系统实现的。相对于 Java 中的零拷贝而言,Netty 的零拷贝更多的是偏向于优化数据操作的概念。

Netty 中的零拷贝体现在以下几个方面:

  • Netty 提供了CompositeByteBuf类,它可以将多个ByteBuf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的复制。

  • 通过wrap操作,可以将 byte [] 数组、ByteBuf、ByteBuffer等包装成一个 Netty ByteBuf 对象,进而避免了复制操作。

  • ByteBuf支持slice操作,因此可以将ByteBuf分解为多个共享同一个存储区域的ByteBuf,避免了内存的复制。

  • 通过FileRegion包装的FileChannel.transferTo()实现文件传输,可以直接将文件缓冲区的数据发送到目标Channel,避免了通过循环 while方式导致的内存复制问题。

从上面几个方法可以看出,前三个方法都是广义零拷贝,其实现方式都是为了减少不必要的数据复制,偏向于应用层数据优化操作。而第四个方法,FileRegion

包装的FileChannel.transferTo(),才是真正的零拷贝(狭义零拷贝)。

下面分别来看其每一种实现。

1、CompositeByteBuf 方式

CompositeByteBuf 将多个ByteBuf合并为一个逻辑上的ByteBuf,类似于用一个链表,把分散的多个ByteBuf通过引用连接起来。分散的多个ByteBuf在内存中可能是大小各异、互不相连的区域,通过链表串联起来,作为一块逻辑上的大区域。而在实际数据读取时,还是会去各自每一小块上读取。

下图展示了 CompositeByteBuf 的原理:

以下是 CompositeByteBuf 使用的代码示例:

ByteBuf header = ...
ByteBuf body = ...
CompositeByteBuf compositeBuffer = Unpooled.compositeBuffer();
compositeBuffer.addComponents(true, header,body);

2、wrap 方式

可以通过 wrap操作来实现零拷贝。

通过 wrap 操作,可以将 byte [] 数组、ByteBuf、ByteBuffer等包装成一个 Netty ByteBuf 对象。

例如,通过 Unpooled.wrappedBuffer方法来将 bytes 包装成为一个UnpooledHeapByteBuf对象,而在包装的过程中,是不会有复制操作的。即最后生成的 ByteBuf 对象是和 bytes 数组共用了同一个存储空间,对 bytes 的修改也会反映到 ByteBuf 对象中。

以下是Unpooled.wrappedBuffer使用的代码示例:

ByteBuf header = ...
ByteBuf body = ...
ByteBuf allByteBuf = Unpooled.wrappedBuffer(header,body);

3、slice 方式

可以通过 slice 方式实现零拷贝,原理图如下:

通过 Slice 操作,将ByteBuf分解为多个共享同一个存储区域的ByteBuf。slice 恰好是将一整块区域,划分成逻辑上的独立小区域,在读取每个逻辑上的小区域时,实际会去按 slice(int index,int length)方法中的indexlength去读取原内存 buffer 的数据。

以下是 slice 使用的示例代码:

ByteBuf bytebuf = ...
ByteBuf header = bytebuf.slice(0,5);
ByteBuf body = bytebuf.slice(5,10);

4、 FileRegion 方式

FileRegion底层包装的是 Java 的FileChannel.transferTo()实现文件传输,因此可以直接将文件缓冲区的数据发送到目标Channel。这种方式才是真正操作系统级别的零拷贝。

以下是FileRegion使用的代码示例:

public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    RandomAccessFile raf = null;
    long length = 0;
    try {
        //1.通过 RandomAccessFile 打开一个文件
        raf = new RandomAccessFile(msg, "r");
        length = raf.length();
    } catch (Exception e) {
        ctx.writeAndFlush("ERR:" + e.getClass() + ": " + e.getMessage());
        return;
    } finally {
        if (length < 0 & raf != null) {
            raf.close();
        }
    }

    ctx.write(raf.length());
    if (ctx.pipeline().get(SslHandler.class) == null) {
        //2.调用 raf.getChannel() 方法获取一个 FileChannel
        //3.将FileChannel封装成一个DefaultFileRegion
        ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length));
    } else {
        ctx.write(new ChunkedFile(raf));
    }
    ctx.write("\n");

}

总结

通过以上的介绍,相信小伙伴们对于Netty的零拷贝机制原理也有了一定的了解,有没有思考一个问题,当我们向缓冲区写入数据时,如果写入的数据超过设置的容量(capacity)怎么办?其实Netty 提供了动态扩容机制,有兴趣的小伙伴们可以自己去了解一下。

我们下节来讲讲Netty的引导程序的源码分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/668938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构练习题1:基本概念

练习题1&#xff1a;基本概念 1 抽象数据类型概念分析2. 逻辑结构与存储结构概念分析3.综合选择题4.综合判断题5.时间复杂度相关习题 1 抽象数据类型概念分析 1.可以用&#xff08;抽象数据类型&#xff09;定义一个完整的数据结构。 分析&#xff1a; 1&#xff09;抽象数据…

【Leetcode -617.合并二叉树 -1022.从根到叶的二进制数之和】

Leetcode Leetcode -617.合并二叉树Leetcode -1022.从根到叶的二进制数之和 Leetcode -617.合并二叉树 题目&#xff1a;给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#x…

ESP32-IDF VS Code进行开发

ESP32-C3 入门篇&#xff08;二&#xff09;使用VS Code进行开发 文章目录 前言 总结STM32的成功&#xff0c;除了Cortex M3的性能强之外&#xff0c;也离不开ST推出的标准库及简单易用的MDK IDE。完善的开发配套&#xff0c;极大的降低了开发门槛&#xff0c;让开发者更专注…

python:使用Scikit-image对遥感影像做空间滤波(中值,高斯,Sobel,Laplace,Scharr等)

作者:CSDN @ _养乐多_ 本文将介绍使用Scikit-image中的滤波函数对遥感影像做空间滤波的代码。滤波方法包括:中值滤波器,高斯滤波器,Sobel滤波器,Laplace滤波器,Scharr滤波器等。并将原始影像和结果影像绘制成图。 结果如下图所示, 文章目录 一、空间滤波函数详解二、…

RocketMQ发送消息

一.消费模式 MQ的消费模式可以大致分为两种&#xff0c;一种是 推Push&#xff0c;一种是 拉Pull。 Push 是 服务端 (MQ) 主动推送消息给客户端&#xff0c;优点是及时性较好&#xff0c;但如果客户端没有做好流控&#xff0c;一旦服务端推送大量消息到客户端时&#xff0c;…

分布式光伏电站智能管理系统

随着能源需求的增加&#xff0c;各种各样的光伏电站工程建设出现不同形式的技术缺陷。设计了分布式光伏电站区域智能系统&#xff0c;实现 了各个园区用电数据的集中管理。对光伏电站分布式运营管理进行了研究&#xff0c;采用集中运营管理中心的方法&#xff0c;建立了区域分布…

蓝牙L2CAP协议简介及报文格式

概述 逻辑链路控制和适配协议&#xff08;Logical Link Control and Adaptation Protocol&#xff0c;L2CAP&#xff09;是蓝牙的核心协议&#xff0c;负责适配基带中的上层协议。它同链路管理器并行工作&#xff0c;向上层协议提供定向连接的和无连接的数据业务。L2CAP具有分…

Baumer工业相机堡盟工业相机如何通过BGAPISDK将相机图像写入相机内存(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK将相机图像写入相机内存&#xff08;C&#xff09; Baumer工业相机Baumer工业相机BGAPISDK和相机内存的技术背景Baumer工业相机通过BGAPISDK将相机图像写入相机内存功能1.引用合适的类文件2.通过BGAPISDK将相机图像写入相机内存功能…

Cortext-M3系统:异常(3)

1、异常 异常响应系统是再M3内核水平上的&#xff0c;支持众多的系统异常和外部中断。1-15为系统异常&#xff0c;大于16为外部中断。除了个别异常的优先级被定死外&#xff0c;其它异常的优先级都是可编程的。优先级数值越小&#xff0c;优先级越高。CM3支持中断嵌套&#xff…

网络嗅探与ARP欺骗

目录 一、网络嗅探概述 1.1 网络嗅探的概念 1.1.2 一把双刃剑 1.1.3 特点 1.2 网络嗅探的原理 1.2.1 网络嗅探的条件 1.2.2 网卡的工作模式 1.2.3 局域网的传输技术 1.3 网络嗅探的前提 1.3.1 网卡设置为混杂模式 1.3.2 同处在一个广播式局域网内 1.4 嗅探工具的使…

4.23 TCP状态转换 4.24半关闭、端口复用

4.23 TCP状态转换 2MSL(Maximum Segment Lifetime) 主动断开连接的一方&#xff0c;最后进入一个TIME_WAIT状态&#xff0c;这个状态会持续&#xff1a;2msl msl&#xff1a;官方建议&#xff1a;2分钟&#xff0c;实际是30s 当 TCP 连接主动关闭方接收到被动关闭方发送的 FIN…

【kubernetes】部署kube-apiserver与kubectl

前言:二进制部署kubernetes集群在企业应用中扮演着非常重要的角色。无论是集群升级,还是证书设置有效期都非常方便,也是从事云原生相关工作从入门到精通不得不迈过的坎。通过本系列文章,你将从虚拟机准备开始,到使用二进制方式从零到一搭建起安全稳定的高可用kubernetes集…

Flutter 组件集录 | RawMagnifier 组件 - 拿起你的八倍镜

theme: cyanosis 1. 前言 今天看 Flutter 源码&#xff0c;偶然发现 Magnifier 组件&#xff0c;这单词不就是 放大镜 嘛! 再结合新版 Flutter 中输入文本的放大镜效果&#xff0c;直觉告诉我这玩意应该可以放大任何组件。如下所示&#xff0c;背景是一张图片&#xff0c;使用 …

0013-TIPS-pawnyable : Race-Condition

原文 Linux Kernel PWN | 040204 Pawnyable之竞态条件 Holstein v4: Race Condition 题目下载 漏洞代码 #include <linux/module.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/uaccess.h> #i…

使用 Vite + Vue3 + Element-Plus + Pinia + Ts 搭建 Vue3 项目

使用 Vite Vue3 Element-Plus Pinia Ts 搭建 Vue3 项目 使用Vite搭建配置Router配置 Element-Plus配置sass配置Pinia配置解析 符号&#xff0c;并找到对应的路径TypeScript忽略类型检查 使用Vite搭建 Vite 需要 Node.js 版本 14.18&#xff0c;16。然而&#xff0c;有些模…

chatgpt赋能python:Python指定小数点位数的完整指南

Python指定小数点位数的完整指南 Python是一种高级编程语言&#xff0c;广泛用于科学、统计和数学计算。在许多情况下&#xff0c;我们需要对浮点数进行更精确的计算。Python 中保留小数位数的能力很强&#xff0c;本文将向您介绍如何在 Python 中指定小数点后的位数。 为什么…

购买服务器/安装宝塔

1、服务器的选择 本人知道并了解一丢丢的就这四个平台&#xff1a; 1、阿里云 2、腾讯云 3、硅云 4、亚马逊 个人觉得阿里云是YYDS&#xff0c;啥都挺方便的&#xff0c;唯一不足就是有点小贵&#xff0c;但是新用户第一次购买还是很优惠的。 腾讯云有的云服务器是真的便宜&am…

【Batch_size 与 梯度 之间的关系】

chatGPT 回答 梯度更新与批大小&#xff08;batch size&#xff09;之间有密切的关系。批大小是指在训练过程中一次迭代所使用的样本数量。 在深度学习中&#xff0c;梯度下降是一种常用的优化算法&#xff0c;用于更新模型参数以最小化损失函数。梯度是损失函数对于模型参数…

Gradio Flagging模块解析与实践

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

基于html+css的图展示135

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…