解析IO零拷贝技术

背景介绍

从字面上我们很容易理解出,零拷贝包含两个意思:

  • 拷贝:就是指数据从一个存储区域转移到另一个存储区域。
  • 零:它表示拷贝数据的次数为 0。

合起来理解,零拷贝就是不需要将数据从一个存储区域复制到另一个存储区域。

最早的零拷贝定义,来源于 Linux 系统的 sendfile 方法逻辑!

在 Linux 2.4 内核中,sendfile 系统调用方法,可以将磁盘数据通过 DMA 拷贝到内核态 Buffer 后,再通过 DMA 拷贝到 NIC Buffer(socket buffer),无需 CPU 拷贝,这个过程被称之为零拷贝。

从这段描述里面我们可以得知,站在操作系统的角度,零拷贝没有说不需要拷贝数据,而是省掉了 CPU 拷贝环节,减少了不必要的拷贝次数,提升数据拷贝效率。

IO 拷贝机制介绍

1、传统数据拷贝流程

以客户端从服务器下载文件为例,服务端需要做两件事:

  • 第一步:从磁盘中读取文件内容
  • 第二步:将文件内容通过网络传输给客户端

事实上看似简单的操作,里面的流程却没那么简单,例如应用程序从磁盘中读取文件内容的操作,大体会经过以下几个流程:

  • 第一步:用户应用程序调用 read 方法,向操作系统发起 IO 请求,CPU 上下文从用户态转为内核态,完成第一次 CPU 切换
  • 第二步:操作系统通过 DMA 控制器从磁盘中读数据,并把数据存储到内核缓冲区
  • 第三步:CPU 把内核缓冲区的数据,拷贝到用户缓冲区,同时上下文从内核态转为用户态,完成第二次 CPU 切换

整个读取数据的过程,完成了 1 次 DMA 拷贝,1 次 CPU 拷贝,2 次 CPU 切换;反之写入数据的过程,也是一样的。

在这里插入图片描述

从上图,我们可以得出如下结论,4 次拷贝次数、4 次上下文切换次数。

  • 数据拷贝次数:2 次 DMA 拷贝,2 次 CPU 拷贝
  • CPU 切换次数:4 次用户态和内核态的切换

而实际 IO 读写,有时候需要进行 IO 中断,同时也需要 CPU 响应中断,拷贝次数和切换次数比预期的还要多,以至于当客户端进行资源文件下载的时候,传输速度总是不尽人意。

2、mmap 内存映射拷贝流程

mmap 内存映射的拷贝,指的是将用户应用程序的缓冲区和操作系统的内核缓冲区进行映射处理,数据在内核缓冲区和用户缓冲区之间的 CPU 拷贝将其省略,进而加快资源拷贝效率。

在这里插入图片描述

mmap 内存映射拷贝流程,从上图可以得出如下结论:

  • 数据拷贝次数:2 次 DMA 拷贝,1 次 CPU 拷贝
  • CPU 切换次数:4 次用户态和内核态的切换

整个过程省掉了数据在内核缓冲区和用户缓冲区之间的 CPU 拷贝环节,在实际的应用中,对资源的拷贝能提升不少。

3、Linux 系统 sendfile 拷贝流程

在 Linux 2.1 内核版本中,引入了一个系统调用方法:sendfile。

当调用 sendfile() 时,DMA 将磁盘数据复制到内核缓冲区 kernel buffer;然后将内核中的 kernel buffer 直接拷贝到 socket buffer;最后利用 DMA 将 socket buffer 通过网卡传输给客户端。

在这里插入图片描述

Linux 系统 sendfile 拷贝流程,从上图可以得出如下结论:

  • 数据拷贝次数:2 次 DMA 拷贝,1 次 CPU 拷贝
  • CPU 切换次数:2 次用户态和内核态的切换

相比 mmap 内存映射方式,Linux 2.1 内核版本中 sendfile 拷贝流程省掉了 2 次用户态和内核态的切换,同时内核缓冲区和用户缓冲区也无需建立内存映射,对资源的拷贝能提升不少。

4、sendfile With DMA scatter/gather 拷贝流程

在 Linux 2.4 内核版本中,对 sendfile 系统方法做了优化升级,引入 SG-DMA 技术,需要 DMA 控制器支持。

其实就是对 DMA 拷贝加入了 scatter/gather 操作,它可以直接从内核空间缓冲区中将数据读取到网卡。使用这个特点来实现数据拷贝,可以多省去一次 CPU 拷贝。

在这里插入图片描述

Linux 系统 sendfile With DMA scatter/gather 拷贝流程,从上图可以得出如下结论:

  • 数据拷贝次数:2 次 DMA 拷贝,0 次 CPU 拷贝
  • CPU 切换次数:2 次用户态和内核态的切换

可以发现,sendfile With DMA scatter/gather 实现的拷贝,其中 2 次数据拷贝都是 DMA 拷贝,全程都没有通过 CPU 来拷贝数据,所有的数据都是通过 DMA 来进行传输的,这就是操作系统真正意义上的零拷贝(Zero-copy) 技术,相比其他拷贝方式,传输效率最佳。

5、Linux 系统 splice 零拷贝流程

在 Linux 2.6.17 内核版本中,引入了 splice 系统调用方法,和 sendfile 方法不同的是,splice 不需要硬件支持。

它将数据从磁盘读取到 OS 内核缓冲区后,内核缓冲区和 socket 缓冲区之间建立管道来传输数据,避免了两者之间的 CPU 拷贝操作。

在这里插入图片描述

Linux 系统 splice 拷贝流程,从上图可以得出如下结论:

  • 数据拷贝次数:2 次 DMA 拷贝,0 次 CPU 拷贝
  • CPU 切换次数:2 次用户态和内核态的切换

Linux 系统 splice 方法逻辑拷贝,也是操作系统真正意义上的零拷贝。

IO 拷贝机制对比

从上面的 IO 拷贝机制可以看出,无论是传统 IO 方式,还是引入零拷贝之后,2次 DMA copy 是都少不了的,唯一的区别就是省掉 CPU 参与环节的方式不同。

在这里插入图片描述

需要注意的地方是,零拷贝所有的方式,都需要操作系统支持,具体采用哪种方式,由操作系统来决定。

相关概念说明

1、DMA 介绍

DMA,英文全称是 Direct Memory Access,即直接内存访问。DMA 本质上是一块主板上独立的芯片,允许外设设备和内存存储器之间直接进行 IO 数据传输,其过程不需要 CPU 的参与。

2、内核空间和用户空间介绍

操作系统的核心是内核,与普通的应用程序不同,它可以访问受保护的内存空间,也有访问底层硬件设备的权限。

为了避免用户进程直接操作内核,保证内核安全,操作系统将虚拟内存划分为两部分,一部分是内核空间(Kernel-space),一部分是用户空间(User-space)。在 Linux 系统中,内核模块运行在内核空间,对应的进程处于内核态;而用户程序运行在用户空间,对应的进程处于用户态。

内核空间总是驻留在内存中,它是为操作系统的内核保留的。应用程序是不允许直接在该区域进行读写或直接调用内核代码定义的函数。

当启动某个应用程序时,操作系统会给应用程序分配一个单独的用户空间,其实就是一个用户独享的虚拟内存,每个普通的用户进程之间的用户空间是完全隔离的、不共享的,当用户进程结束的时候,用户空间的虚拟内存也会随之释放。

同时处于用户态的进程不能访问内核空间中的数据,也不能直接调用内核函数的,如果要调用系统资源,就要将进程切换到内核态,由内核程序来进行操作。

Java 零拷贝实现介绍

Linux 提供的零拷贝技术,Java 并不是全部支持,目前只支持以下 2 种。

  • mmap(内存映射)
  • sendfile

1、Java NIO 对 mmap 的支持

Java NIO 有一个MappedByteBuffer的类,可以用来实现内存映射。它的底层是调用了 Linux 内核的mmap的 API。

实例代码如下:

  public static void main(String[] args) {try {FileChannel readChannel = FileChannel.open(Paths.get("a.txt"), StandardOpenOption.READ);// 建立内存文件映射MappedByteBuffer data = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, 1024 * 1024 * 40);FileChannel writeChannel = FileChannel.open(Paths.get("b.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);// 拷贝数据writeChannel.write(data);// 关闭通道readChannel.close();writeChannel.close();}catch (Exception e){System.out.println(e.getMessage());}}

其中MappedByteBuffer的作用,就是将内核缓冲区的内存和用户缓冲区的内存做了一个地址映射,读取小文件,效率并不高;但是读取大文件,效率很高。

2、Java NIO 对 sendfile 的支持

Java NIO 中的FileChannel.transferTo方法,底层调用的就是 Linux 内核的sendfile系统调用方法。Kafka 这个开源项目就用到它(Kafka为什么快:sendfile零拷贝系统调用方法)

实例代码如下:

  public static void main(String[] args) {try {// 原始文件FileChannel srcChannel = FileChannel.open(Paths.get("a.txt"), StandardOpenOption.READ);// 目标文件FileChannel destChannel = FileChannel.open(Paths.get("b.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);// 拷贝数据srcChannel.transferTo(0, srcChannel.size(), destChannel);// 关闭通道srcChannel.close();destChannel.close();} catch (Exception e) {System.out.println(e.getMessage());}}

Java NIO 提供的FileChannel.transferTo并不保证一定能使用零拷贝。实际上是否能使用零拷贝与操作系统相关,如果操作系统提供sendfile这样的零拷贝系统调用方法,那么会充分利用sendfile零拷贝的优势,否则并不能实现零拷贝。

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

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

相关文章

练习LabVIEW第三十六题

学习目标: 刚学了LabVIEW,在网上找了些题,练习一下LabVIEW,有不对不好不足的地方欢迎指正! 第三十六题: 使用labview模拟温度采集系统,要求有停止键 开始编写: 前面板放一个温度…

day-81 打家劫舍 II

思路 与LCR 089. 打家劫舍相比,本题所有房屋围成了一圈,那么第一间房子和最后一间房子不能同时打劫,那么就可以分为两种情况:1.选第一间房打劫;2.选最后一间房打劫 解题过程 然后依次计算出以上两种情况的最大金额&am…

linux网络编程自定义协议和多进程多线程并发-TCP编程

1.三次握手及后面过程 计算机A是客户端, B是服务端 1.1三次握手: 1客户端给服务端SYN报文 2服务端返回SYNACK报文 3客户端返回ACK报文 客户端发完ACK后加入到服务端的维护队列中,accept()调用后就能和客户端建立连接,然后建立通讯 1.2关闭…

【工具】批量网址打开器,一次打开多个网址链接

假如你有很多个网址,这些网址要全部打开,你是否会每次复制一个粘贴到浏览器地址栏,再去复制下一个粘贴到地址栏,这样重复的操作?我就有这样的困扰,比如要检查网页上是否有bug,就要一个一个的点开…

「Mac畅玩鸿蒙与硬件24」UI互动应用篇1 - 灯光控制小项目

本篇将带领你实现一个互动性十足的灯光控制小项目,用户可以通过点击按钮来控制灯光的开关。该项目将涉及状态管理、动态图片加载以及按钮交互,是学习鸿蒙应用开发的重要基础。 关键词 UI互动应用状态管理动态图片加载用户交互 一、功能说明 在这个灯光…

如何从0到1开发一款智能生产小工单系统——全网最详细教程!

在生产车间,工单管理一度是个让人头疼的问题。任务分配不清、生产流程混乱、交接环节不顺畅等问题,让管理人员和一线工人疲于奔命。而一个智能的生产小工单系统正是解决这些问题的利器。不仅能有效地理顺工单流转流程,还能大幅提升工作效率和…

SpringBoot基础系列学习(五):JdbcTemplate 访问数据库

文章目录 一丶介绍二丶引入依赖三丶配置配置文件四丶创建表五丶java代码 一丶介绍 Spring Boot作为Spring的集大成者,自然会将JdbcTemplate集成进去。Spring Boot针对JDBC的使用提供了对应的Starter包:spring-boot-starter-jdbc,它其实就是在…

win11电脑无法找到声音输出设备怎么办?查看解决方法

电脑无法找到声音输出设备是一个常见的问题,尤其是在使用Windows操作系统时。幸运的是,大部分问题都可以通过以下几种方法来解决。 一、检查物理连接 在深入诊断之前,首先要检查硬件连接是否正常。这包括: 确保耳机、扬声器或其…

二叉树相关习题

题目:100. 相同的树 - 力扣(LeetCode) 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 示例 1: …

数据结构和算法(六):贪心算法、分治算法、回溯算法、动态规划、拓扑排序

从广义上来讲:数据结构就是一组数据的存储结构 , 算法就是操作数据的方法 数据结构是为算法服务的,算法是要作用在特定的数据结构上的。 10个最常用的数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie树 10个最…

PPT素材、模板免费下载!

做PPT一定要收藏好这6个网站,PPT模板、素材、图表、背景等超多素材全部免费下载。 1、菜鸟图库 ppt模板免费下载|ppt背景图片 - 菜鸟图库 菜鸟图库网有非常丰富的免费素材,像设计类、办公类、自媒体类等素材都很丰富。PPT模板种类很多,全部都…

Prompt Engineering介绍

什么是Prompt Engineering? 近年来,大语言模型(LLM)发展迅速,成为自然语言处理领域的重要技术。除了OpenAI的GPT系列、Google的PaLM(Pathways Language Model)和Bard,国内也涌现出多…

Golang | Leetcode Golang题解之第540题有序数组中的单一元素

题目&#xff1a; 题解&#xff1a; func singleNonDuplicate(nums []int) int {low, high : 0, len(nums)-1for low < high {mid : low (high-low)/2mid - mid & 1if nums[mid] nums[mid1] {low mid 2} else {high mid}}return nums[low] }

【Springboot问题】创建springboot项目后没有Resources文件夹及application文件

问题描述&#xff1a; 在创建springboot项目之后&#xff0c;由于项目识别的问题&#xff0c;没有出现资源文件夹以及application文件。 解决方法&#xff1a; 但是此刻依旧没有application.yml文件&#xff0c;创建

「C/C++」C/C++之 数组赋值给std::vector多种方法

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

2024国际超模大赛亚洲总决赛在成都举行,国外选手对成都印象深刻!

11月3日&#xff0c;2024国际超模大赛亚洲总决赛在成都环球中心洲际酒店成功落下帷幕。从全国2000多名参赛选手中脱颖而出&#xff0c;历经多赛段、多环节层层选拔&#xff0c;晋级的各组获奖选手惊艳亮相总决赛。2024国际超模大赛亚洲总决赛&#xff0c;是一场现象级传播地方特…

Unity3D学习FPS游戏(8)装弹和弹夹UI显示

前言&#xff1a;实现了武器的基本发射功能&#xff0c;但是我们弹夹数量是有限&#xff0c;之前并没有做装弹和弹夹显示的功能。本篇实现装弹和弹夹显示。 装弹和弹夹UI显示 装弹目标思路和实现 弹夹UI显示目标弹夹UI的思路和实现UI代码的思路和实现 武器控制的完整代码效果补…

GameFramework教程☀️福利(五):关于该框架的一些意义

文章目录 📢 不同模式的意义本章探讨GF这样编写的意义和使用场景。 📢 不同模式的意义 最近在做一个app,现在在调研阶段。 代码上后期可能用华佗进行C#热更新。 在调研华佗打包完的热更代码如何和UI AB结合起来时,看到了: "> 从这一点可以延伸理解出,当我们使…

加密货币行业与2024年美国大选

加密货币行业经历了近十年的飞速发展&#xff0c;尤其是在比特币、以太坊等主要加密资产的兴起之后&#xff0c;越来越多的美国人开始将其视为一种财富积累或交易的工具。然而&#xff0c;尽管这一新兴行业的市场规模在持续扩大&#xff0c;但加密货币仍面临着重重监管难题&…

开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序与私域流量圈层

摘要&#xff1a;本文探讨了私域流量圈层的特点以及其在当今时代的重要性&#xff0c;分析了开源 AI 智能名片 21 链动模式 S2B2C 商城小程序源码在私域流量圈层构建中的作用&#xff0c;阐述了产品在圈层时代被标签化的现象&#xff0c;并以实例展示了如何利用该小程序源码打造…