IO零拷贝

news2024/10/6 14:27:06

在介绍零拷贝之前我们先看看传统的 Java 网络 IO 编程是怎样的。

下面代码展示了一个典型的 Java 网络程序。

    File file = new File("index.jsp");
    RandomAccessFile rdf = new RandomAccessFile(file, "rw");

    byte[] arr = new byte[(int) file.length()];
    rdf.read(arr);

    Socket socket = new ServerSocket(8080).accept();
    socket.getOutputStream().write(arr);

程序中调用 RandomAccessFile 的 read 方法将 index.jsp 的内容读取到字节数组中。然后调用 write 方法将字节数组中的数据写入到 Socket 对应的输出流中发送给客户端。那么 Java 应用程序中的 read、write 方法对应到 OS 底层是怎样的呢。下图展示了这个过程。
在这里插入图片描述
图中上半部分记录了用户态和内核态的上下文切换。下半部分展示了数据的复制过程。上述 Java 代码对应的操作系统底层步骤:

  1. read 方法触发操作系统从用户态到切换到内核态。同时通过 DMA 的方式从磁盘读取文件到内核缓冲区。DMA(Direct Memory Access)是 l/O 设备与主存之间由硬件组成的直接数据通路。即不需要 CPU 拷贝数据到内存,而是直接由 DMA 引擎传输数据到内存。

  2. 紧接着发生第二次数据拷贝,即从内核缓冲区拷贝到用户缓冲区,同时发生一次内核态到用户态的上下文切换。

  3. 调用 write 方法时,触发第三次数据拷贝,即从用户缓冲区拷贝到 Socket 缓冲区。同时发生一次用户态到内核态的上下文切换。

  4. 最后数据从 Socket 缓冲区异步拷贝到网络协议引擎,这一步采用的是 DMA 方式。同时没有发生上下文切换。

  5. write 方法返回时,触发了最后一次内核态到用户态的切换。

由此可见,复制的操作太频繁,共有 2 次 DMA 拷贝、2 次 CPU 拷贝、4 次上下文切换。能否优化呢?

这就要介绍称之为"零拷贝"的技术。首先声明,零拷贝技术依赖底层 OS 内核提供的支持。Linux 中提供的这类支持有 mmap(),sendfile() 以及 splice() 系统调用。说白了就是减少数据在操作系统内核的缓冲区和用户应用程序地址空间的缓冲区之间进行拷贝。

mmap

mmap 通过内存映射,将文件通过 DMA 的方式映射到内核缓冲区。操作系统会把这段内核缓冲区与应用程序(用户空间)共享。这样,在进行网络传输时,就能减少内核空间到用户空间的拷贝次数。此时输出数据时只要从内核缓冲区拷贝到 Socket 缓冲区即可。可见减少了一次 CPU 拷贝,但是上下文切换次数并没有减少。整个过程共 2 次 DMA 拷贝,1 次 CPU 拷贝,4 次上下文切换。示意图如下。
在这里插入图片描述

sendFile

Linux 2.1 开始提供了 sendFile 函数,其基本原理是:数据根本不经过用户态,直接从 Kernel Buffer 进入到 Socket Buffer,并且由于和用户态完全无关,这就避免了一次上下文切换。下图展示了整个过程。磁盘中的数据通过 DMA 引擎从复制到内核缓冲区。调用 write 方法时从内核缓冲区拷贝到 Socket 缓冲区。由于在同一个空间,因此没有发生上下文切换。最后由 Socket 缓冲区拷贝到协议引擎。整个过程共发生了 2 次 DMA 拷贝,1 次 CPU 拷贝,3 次上下文切换。
在这里插入图片描述

在 Linux 2.4 版本中,进一步做了优化。从 Kernel Buffer 拷贝到 Socket Buffer 的操作也省了,直接拷贝到协议栈,再次减少了 CPU 数据拷贝。下图展示了整个流程。本地文件 index.jsp 要传输到网络中,只需 2 次拷贝。第一次是 DMA 引擎从文件拷贝到内核缓冲区;第二次是从内核缓冲区将数据拷贝到网络协议栈;内核缓存区只会拷贝一些元信息,比如 offset 和 length 信息到 SocketBuffer,基本无消耗。
在这里插入图片描述

综上所述,最后一种方式发生了 2 次 DMA 拷贝、0 次 CPU 拷贝、3 次上下文切换。这就是所谓的“零拷贝”实现。

总结:

因此零拷贝通常是站在操作系统的角度看,即整个过程中,内核缓冲区之间是没有重复数据的。同时伴随着更少的上下文切换。这就带来了 IO 性能质的提升!

实际开发中,mmap 和 sendFile 都有应用,可以认为是“零拷贝”的两种实现方式。它们都有各自的适用场景。mmap 更适合少量数据读写,sendFile 适合大文件传输。sendFile 可以利用 DMA 方式将内核缓冲区将数据拷贝到网络协议栈,减少 CPU 拷贝,而 mmap 则不能(必须从内核拷贝到 Socket 缓冲区)。

案例:

RocketMQ 在 CommitLog 和 CosumerQueue 的实现中都采用了 mmap。而 Kafka 的零拷贝实现则使用了 sendFile。

RocketMQ 和 Kafka 高性能的原因之一便是顺序写入和近似顺序读取 + 零拷贝。


引用:https://zhuanlan.zhihu.com/p/543661648

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

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

相关文章

遗留系统现代化:7步入门数字化转型

遗留系统对企业来说可能是一把双刃剑。虽然它们曾经对企业很有帮助,但随着时间的推移,这些应用程序、系统和架构变得过时,最终会限制企业发展。 为了实现保持竞争优势所需的扩展、业务敏捷性和数字化转型,越来越多企业意识到需要…

【初阶C++】入门(超详解)

C入门 前言1. C关键字(C98)2. 命名空间2.1 命名空间定义2.2 命名空间使用2.3嵌套命名空间 3. C输入&输出4. 缺省参数4.1 缺省参数概念4.2 缺省参数分类 5. 函数重载5.1 函数重载概念5.2 C支持函数重载的原理--名字修饰(name Mangling) 6. 引用6.1 引用概念6.2 引用特性6.3 …

C/C++ 表达式求值(含多位数)

个人主页:仍有未知等待探索_C语言疑难,数据结构,算法-CSDN博客 专题分栏:算法_仍有未知等待探索的博客-CSDN博客 目录 一、前言 二、解析 分析 最后直接上代码! 一、前言 表达式求值是一个比较基础的代码关于栈的使用。在写的时候充分锻炼…

mybatis动态SQL-trim

1、建库建表 create database mybatis-example; use mybatis-example; create table emp (empNo varchar(40),empName varchar(100),sal int,deptno varchar(10) ); insert into emp values(e001,张三,8000,d001); insert into emp values(e002,李四,9000,d001); insert into…

Dueling DQN 跑 Pendulum-v1

gym-0.26.1 Pendulum-v1 Dueling DQN 因为还是DQN,所以我们沿用double DQN,然后把 Qnet 换成 VAnet。 其他的不变,详情参考前一篇文章。 class VA(nn.Module):"""只有一层隐藏层的A网络和V网络"""def __init__(self, state_dim, hidd…

配电房电力智能运维系统

配电房电力智能运维系统是一种采用先进的信息技术手段,对配电房的电力设备进行实时监控、数据分析和管理的系统。它能够提高电力设备的安全性和效率,降低运维成本,为用户提供更加优质、高效的电力服务。 该系统依托智能运维工具-电易云&#…

Tomcat头上有个叉叉

问题原因: 这是因为它就是个空的tomcat,并没有导入项目运行 解决方案: war模式:发布模式,正式发布时用,将WEB工程以war包的形式上传到服务器 war exploded模式:开发时用,将WEB工程的文件夹直接…

Python 自动化之修理PDF文件(二)

PDF文件_合并与拆分PDF文档Pro版本 文章目录 PDF文件_合并与拆分PDF文档Pro版本前言一、要做成什么样子二、主要用到的函数三、基本思路1.引入库2.创建用户输入模块3.确定主框架 四、文档合并代码模块1.用户输入和函数调用2.引导用户输入文档信息3.合并文档内容4.命名新文档生成…

大数据机器学习深度解读DBSCAN聚类算法:技术与实战全解析

大数据机器学习深度解读DBSCAN聚类算法:技术与实战全解析 一、简介 在机器学习的众多子领域中,聚类算法一直占据着不可忽视的地位。它们无需预先标注的数据,就能将数据集分组,组内元素相似度高,组间差异大。这种无监…

Springboot日志篇

一、概述 1.1简介 市场上存在非常多的日志框架。 JUL(java.util.logging),JCL(ApacheCommons Logging),Log4j,Log4j2,Logback、SLF4j、jboss-logging等。 Spring Booti在框架内容部使用JCL,spring-boot-starter--logging采用了slf4jlogback的形式,Spring Boot也能自…

算法笔记—链表、队列和栈

链表、队列和栈 1. 链表1.1 单链表反转1.2 双链表反转1.3 合并两个有序链表1.4 链表相加1.5 划分链表 2. 队列和栈2.1 循环队列2.2 栈实现队列2.3 队列实现栈2.4 最小栈2.2 双端队列 1. 链表 1.1 单链表反转 力扣 反转链表 // 反转单链表public ListNode reverseList(ListNod…

达索系统SOLIDWORKS 2024 Visualize新功能

SOLIDWORKS Visualize(原名为 Bunkspeed)是一整套独立的软件工具,Visualize模块主要是用于对SOLIDWORKS设计出的产品图进行渲染、做动画,方便用户更好的展示、宣传产品;以最快速、最轻松的方式创建专业的照片级图像、动…

〖大前端 - 基础入门三大核心之JS篇(53)〗- 构造函数与类

说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费,如需要项目实战或者是体系化资源,文末名片加V!作者:哈哥撩编程,十余年工作经验, 从事过全栈研发、产品经理等工作,目前在公司…

【论文阅读笔记】M3Care: Learning with Missing Modalities in Multimodal Healthcare Data

本文介绍了一种名为“MCare”的模型,旨在处理多模态医疗保健数据中的缺失模态问题。这个模型是端到端的,能够补偿病人缺失模态的信息,以执行临床分析。MCare不是生成原始缺失数据,而是在潜在空间中估计缺失模态的任务相关信息&…

【知识积累】深度度量学习综述

原文指路:https://hav4ik.github.io/articles/deep-metric-learning-survey Problem Setting of Supervised Metric Learning 深度度量学习是一组旨在衡量数据样本之间相似性的技术。 Contrastive Approaches 对比方法的主要思想是设计一个损失函数,直…

STM32——震动传感器点亮LED灯

震动传感器简单介绍 若产品不震动,模块上的 DO 口输出高电平; 若产品震动,模块上的 DO 口输出低电平,D0-LED绿色指示灯亮。 震动传感器与STM32的接线 编程实现 需求:当震动传感器接收到震动信号时,使用中断…

Ubuntu 22安装PHP环境

参考博客为《练习 0(2/2):Ubuntu 环境下安装PHP(PHP-FPM)》和《原生态Ubuntu部署LAMP环境 PHP8.1MySQLApache》 sudo apt-get install -y php7.4想要安装php7.4,发现安装的是php8.1。 完成如下图&#xf…

构思3年,巨 TM 好用的 localStorage 封装!!!

localStorage 和 sessionStorage 作为一个本地存储方案,所有的操作都是同步的,用法也非常简单,所以深受广大前端的喜爱。 但是由于 localStorage 只能存储字符串,所以存储其他数据就比较麻烦。比如我们要存储一个对象的话可能需要…

【程序人生】还记得当初自己为什么选择计算机?

✏️ 初识计算机: 还记得人生中第一次接触计算机编程是在高中,第一门编程语言是Python(很可惜由于条件限制的原因,当时没能坚持学下去......现在想来有点后悔,没能坚持,唉......)。但是&#xf…

STM32G030C8T6:使用外部晶振配置LED灯闪烁

本专栏记录STM32开发各个功能的详细过程,方便自己后续查看,当然也供正在入门STM32单片机的兄弟们参考; 本小节的目标是,使用STM32G030C8T6单片机,通过STM32CubeMX软件,配置并使用外部8MHz晶振,实…