美团面试:说说Netty的零拷贝技术?

news/2025/3/11 6:06:59/文章来源:https://www.cnblogs.com/vipstone/p/18237139

零拷贝技术(Zero-Copy)是一个大家耳熟能详的技术名词了,它主要用于提升 IO(Input & Output)的传输性能。

那么问题来了,为什么零拷贝技术能提升 IO 性能?

1.零拷贝技术和性能

在传统的 IO 操作中,当我们需要读取并传输数据时,我们需要在用户态(用户空间)和内核态(内核空间)中进行数据拷贝,它的执行流程如下:

从上述流程我们可以看出,在传统的 IO 操作中,我们是需要 4 次拷贝和 4 次上下文切换(用户态和内核态的切换)的。

而每次数据拷贝和上下文切换都有时间成本,会让程序的执行时间变成,所以零拷贝技术的出现就是为了减少数据的拷贝次数以及上下文的切换次数的。

1.1 什么是用户态和内核态?

操作系统有用户态和内核态之分,这是因为计算机体系结构中的操作系统设计了两个不同的执行环境,以提供不同的功能和特权级别。

  • 用户态(User Mode)是指应用程序运行时的执行环境。在用户态下,应用程序只能访问受限资源,如应用程序自身的内存空间、CPU 寄存器等,并且不能直接访问操作系统的底层资源和硬件设备。
  • 内核态(Kernel Mode)是指操作系统内核运行时的执行环境。在内核态下,操作系统具有更高的权限,可以直接访问系统的硬件和底层资源,如 CPU、内存、设备驱动程序等。

1.2 什么是DMA?

DMA(Direct Memory Access,直接内存访问)技术,绕过 CPU,直接在内存和外设之间进行数据传输。这样可以减少 CPU 的参与,提高数据传输的效率。

2.Linux零拷贝技术

Linux 下实现零拷贝的主要实现技术是 MMap、sendFile,它们的具体介绍如下。

2.1 MMap

MMap(Memory Map)是 Linux 操作系统中提供的一种将文件映射到进程地址空间的一种机制,通过 MMap 进程可以像访问内存一样访问文件,而无需显式的复制操作。

使用 MMap 可以把 IO 执行流程优化成以下执行步骤:

传统的 IO 需要四次拷贝和四次上下文(用户态和内核态)切换,而 MMap 只需要三次拷贝和四次上下文切换,从而能够提升程序整体的执行效率,并且节省了程序的内存空间。

2.2 senFile 方法

在 Linux 操作系统中 sendFile() 是一个系统调用函数,用于高效地将文件数据从内核空间直接传输到网络套接字(Socket)上,从而实现零拷贝技术。这个函数的主要目的是减少 CPU 上下文切换以及内存复制操作,提高文件传输性能。

使用 sendFile() 可以把 IO 执行流程优化成以下执行步骤:

3.Netty零拷贝技术

Netty 中的零拷贝和传统 Linux 的零拷贝技术的实现不太一样,Netty 中的零拷贝技术主要是通过优化用户态的操作来提升 IO 的执行速度,从而实现零拷贝的

PS:所有可以提升 IO 执行效率的操作或手段都可以称之为零拷贝技术。

Netty 中的零拷贝技术主要有以下 5 种实现:

  1. 使用堆外内存:避免 JVM 堆内存到堆外内存的数据拷贝,从而提升了 IO 的操作性能。
  2. 使用 CompositeByteBuf 合并对象:可以组合多个 Buffer 对象合并成一个逻辑上的对象,避免通过传统内存拷贝的方式将几个 Buffer 合并成一个大的 Buffer。
  3. 通过 Unpooled.wrappedBuffer 合并数据:可以将 byte 数组包装成 ByteBuf 对象,包装过程中不会产生内存拷贝。
  4. 使用 ByteBuf.slice 共享对象:操作与 Unpooled.wrappedBuffer 相反,slice 操作可以将一个 ByteBuf 对象切分成多个 ByteBuf 对象,切分过程中不会产生内存拷贝,底层共享一个 byte 数组的存储空间。
  5. 使用 FileRegion 实现零拷贝:FileRegion 底层封装了 FileChannel#transferTo() 方法,可以将文件缓冲区的数据直接传输到目标 Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝,这属于操作系统级别的零拷贝。

它们的具体实现如下。

3.1 使用堆外内存

正常情况下,JVM 需要将数据从 JVM 堆内存拷贝到堆外内存进行业务执行的,这是因为:

  1. 操作系统并不感知 JVM 的堆内存,而且 JVM 的内存布局与操作系统所分配的是不一样的,操作系统并不会按照 JVM 的行为来读写数据。
  2. 同一个对象的内存地址随着 JVM GC 的执行可能会随时发生变化,例如 JVM GC 的过程中会通过压缩来减少内存碎片,这就涉及对象移动的问题了。

而 Netty 在进行 I/O 操作时都是使用的堆外内存,可以避免数据从 JVM 堆内存到堆外内存的拷贝。

3.2 使用CompositeByteBuf合并对象

CompositeByteBuf 可以理解为一个虚拟的 Buffer 对象,它是由多个 ByteBuf 组合而成,但是在 CompositeByteBuf 内部保存着每个 ByteBuf 的引用关系,从逻辑上构成一个整体。使用 CompositeByteBuf 我们可以合并两个 ByteBuf 对象,从而避免两个对象合并时需要两次 CPU 拷贝操作的问题,在没有使用 CompositeByteBuf 时,我们的操作是这样的:

ByteBuf httpBuf = Unpooled.buffer(header.readableBytes() + body.readableBytes());
httpBuf.writeBytes(header);
httpBuf.writeBytes(body);

而实现 header 和 body 这两个 ByteBuf 的合并,需要先初始化一个新的 httpBuf,然后再将 header 和 body 分别拷贝到新的 httpBuf。合并过程中涉及两次 CPU 拷贝,这非常浪费性能,所以我们就可以使用 CompositeByteBuf 了,它的使用如下:

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

CompositeByteBuf 通过调用 addComponents() 方法来添加多个 ByteBuf,但是底层的 byte 数组是复用的,不会发生内存拷贝。

3.3 通过Unpooled.wrappedBuffer合并数据

Unpooled.wrappedBuffer 的操作类似,使用它可以将不同的数据源的一个或者多个数据包装成一个大的 ByteBuf 对象,其中数据源的类型包括 byte[]、ByteBuf、ByteBuffer。包装的过程中不会发生数据拷贝操作,包装后生成的 ByteBuf 对象和原始 ByteBuf 对象是共享底层的 byte 数组。

3.4 使用 ByteBuf.slice 共享对象

ByteBuf.slice 和 Unpooled.wrappedBuffer 的逻辑正好相反,ByteBuf.slice 是将一个 ByteBuf 对象切分成多个共享同一个底层存储的 ByteBuf 对象,从而避免对象分割时的数据拷贝,它的使用如下:

ByteBuf httpBuf = ...
ByteBuf header = httpBuf.slice(0, 6);
ByteBuf body = httpBuf.slice(6, 4);

3.5 使用 FileRegion 实现文件零拷贝

FileRegion 底层封装了 FileChannel#transferTo() 方法,可以将文件缓冲区的数据直接传输到目标 Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝,这属于操作系统级别的零拷贝。

以下是 FileRegion 的默认实现类 DefaultFileRegion 的使用案例:

@Override
public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {RandomAccessFile raf = null;long length = -1;try {raf = new RandomAccessFile(msg, "r");length = raf.length();} catch (Exception e) {ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n');return;} finally {if (length < 0 && raf != null) {raf.close();}}ctx.write("OK: " + raf.length() + '\n');if (ctx.pipeline().get(SslHandler.class) == null) {// SSL not enabled - can use zero-copy file transfer.ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length));} else {// SSL enabled - cannot use zero-copy file transfer.ctx.write(new ChunkedFile(raf));}ctx.writeAndFlush("\n");}

从上述代码可以看出,可以通过 DefaultFileRegion 将文件内容直接写入到 NioSocketChannel 中,从而避免了内核缓冲区和用户态缓冲区之间的数据拷贝。

课后思考

那么问题来了,FileRegion 是如何实现零拷贝的呢?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频大模型 Vidu 支持音视频合成;字节跳动推出语音生成模型 Seed-TTS 丨 RTE 开发者日报 Vol.221

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点…

基于 fastflow 的一种工作流框架

Why do we use "reconcile" in Cloud? 让我们思考下在云上为用户提供一种中间件服务,我们需要做什么?按照顺序编排申请各类云资源 —— 网络,S3,K8S,计算,存储 ……。 在 K8S 中自动化部署中间部署 完成各种初始化配置可以想象出看出在 Cloud 上为用户提供服务…

代码高手的过节秘籍:CodeArt Snap帮写代码,灵感弹指间实现

华为云基于大模型技术,学习了1300多万篇经典的技术文档、760亿行精选代码,打造了智能开发助手CodeArts Snap。本文分享自华为云社区《【端午特辑】代码高手的过节秘籍:CodeArt Snap帮写代码,灵感弹指间实现》,作者: 华为云社区精选。 端午将至,粽叶飘香,你却还在为一行…

[GHCTF 2024 新生赛]理想国 flask session伪造

忙着毕业论文几天没做题了。 进入页面发现几个api接口,注册登录搜索登出4个。利用postman访问注册接口注册。可以看到返回了token,利用token访问login。尝试search页面传入file参数试试能不能目录穿越。得到secret-key,这里有个非预期解,访问/proc/1/environ直接得到flag。预…

Arduino UNO和Nano的区别

Arduino UNO 和 Arduino NANO 的区别 ATmega328p UNO对于用过Arduino开发板的小伙伴来说应该是比较熟悉的了,主要说说NANO,UNO和NANO控制芯片同样用的ATmega328p,不同的是芯片封装不同,UNO是DIP28封装 NANO是TQFP32封装(NANO比UNO多了4个引脚出来)图 Arduino Uno图 Arduino…

避免图纸外泄:企业加密软件选择的4条建议

在当今竞争激烈的商业环境中,企业的核心图纸和技术资料是其竞争力的关键。然而,随着信息技术的发展,图纸外泄的风险也日益增加。为了有效保护这些宝贵的无形资产,企业必须选择适合的加密软件。以下是一些专业的建议,帮助企业在选择图纸加密软件时做出明智的决策。一、加密…

阿里400+天,我为什么离开阿里

阿里还是挺不错了,感谢公司,感谢同事们! 零丶前言 今天是我在阿里的lastday,明天我将回成都(此处嘴角弯,我爱成都),端午后入职另外一家互联网大厂。 在去年3月份的时候,我从成都的某家金融科技银行跳槽到杭州阿里巴巴淘天集团,这篇《跳槽!阿里工作100+天,菜鸡职业生涯…

在线RSA公钥私钥生成工具

在线RSA非对称加密公钥私钥生成工具,提供便捷、安全的公私钥生成服务。支持多种密钥长度选择,满足个性化需求。一键生成PEM格式证书,让您快速实现数据加密与身份验证,保障数据安全,提升网络安全防护能力。在线RSA公钥私钥生成工具

自媒体必用的50 个最佳 ChatGPT 社交媒体帖子提示prompt通用模板教程

ChatGPT不仅能帮你快速生成高质量的内容,还能给你带来创意灵感,让每一个社交媒体帖子都变得与众不同。不管你是想写一个吸引眼球的标题,还是想问个有趣的问题,或者分享一句励志的名言,ChatGPT都能帮你搞定。在这个信息爆炸的时代,社交媒体已经成为我们生活中不可或缺的一…

数据治理--模板

支持重跑 建临时表的方式

【日记】遇到了一个很奇怪的大爷(845 字)

正文花了昨天和今天两天时间,把数据转移完了。这块 2T 的硬盘可以光荣退休了。目前是没什么存储焦虑了。农发行净开发一些垃圾系统。今天没什么业务,但跟 ActiveX 斗智斗勇了一整天,最后实在搞不过 IE 浏览器。我也懒得管了,又不多挣一份工资。晚上去跳舞,才注意到老师的妻…

面试必会 --> MyBatis篇

什么是MyBatisMybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。MyBatis 可以使用 XML 或注解来…