DMA 和 零拷贝技术 到 网络大文件传输优化

文章目录

  • DMA 控制器的发展
    • 无 DMA 控制器 IO 过程
    • DMA 控制器
  • 传统文件传输性能有多糟糕?
    • 如何优化文件传输性能
    • 零拷贝技术
      • mmap + write
      • sendfile
        • SG-DMA(The Scatter-Gather Direct Memory Access)
      • 零拷贝技术的应用
  • 大文件传输应该用什么方式
    • PageCache(内核缓冲区) 的作用
    • 直接 I/O
      • 直接 I/O 适用场景
    • 综上所述
    • Nginx 中的零拷贝技术和直接 I/O
  • 个人简介

DMA 控制器的发展

无 DMA 控制器 IO 过程

  • 用户进程发起 read 调用,向操作系统发送 I/O 请求,进程进入阻塞状态;
  • 操作系统收到请求后,CPU 发出对应的控制指令给磁盘控制器, CPU 释放执行其它任务。
  • 磁盘控制器收到指令后,开始准备数据并将数据放入磁盘控制器的内部缓冲区,然后产生一个中断。
  • CPU 收到中断信号后,将磁盘控制器缓冲区的数据读入寄存器,再从寄存器写入到内核缓冲区,这个过程 CPU 无法处理其它的事情。
  • 当内核缓冲区中有足够多的数据后,CPU 将内核缓冲区的数据拷贝到用户缓冲区中。

DMA 控制器

  • 如果 CPU 搬运的数据很小,那么问题并不大,但是如果需要拷贝大量数据肯定是不行的,因为 CPU 的资源十分宝贵。为了解决这个问题,于是出现了 DMA(Direct Memory Access,直接内存访问) 技术。
  • 简单来说就是:在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。
  • 使用 DMA 控制器后,数据传输过程如下:

  • 用户进程发起 read 调用,向操作系统发送 I/O 请求,进程进入阻塞状态;
  • 操作系统收到请求后,CPU 发送一个请求给 DMA , CPU 释放执行其它任务。
  • DMA 进一步将 I/O 请求发送磁盘控制器,磁盘控制器收到指令后,开始准备数据并将数据放入磁盘控制器的内部缓冲区,然后产生一个中断。
  • DMA 收到中断信号后将磁盘控制器缓冲区的数据拷贝到内核缓存区(此时不占用 CPU 资源,CPU 可以执行其它任务)。
  • 当 DMA 读取到足够多的数据到内核缓冲区后,发送中断信号给 CPU ,CPU 将内核缓冲区的数据拷贝到用户缓冲区中。
注:早期 DMA 只存在于主板上,现在 I/O 设备越来越多,数据传输需求也越来越复杂,所以每个 I/O 设备中都有自己的 DMA 控制器。

传统文件传输性能有多糟糕?

  • 现在,大家思考一下,如果我们服务器需要提供文件传输功能,应该怎么做?最简单的方式就是将磁盘上的文件读取出来,然后通过网络协议发送给客户端。通常涉及以下两个系统调用:
read(file, tmp_buf, len);
write(socket, tmp_buf, len);
  • 具体流程图如下:

  • 我们来看看整个过程发生了什么,发生了 2 次系统调用(4 次上下文切换),4 次数据拷贝(2 次 CPU 拷贝,2 次 DMA 拷贝)。
  • 虽然一次上下文切换的时间很短,几十纳秒到几微秒,但在高并发场景下,很容易影响性能。同时我们发现我们虽然只是传输了一份数据,但却拷贝了 4 次,毫无疑问过多的数据拷贝将会占用我们的 CPU 资源。
  • 因此,如果我们想要优化整个文件传输过程,那么主要的优化思路就是减少用户态和内核态的上下文切换以及减少数据拷贝。

如何优化文件传输性能

  • 上面我们说到想要优化整个文件传输过程,主要的优化思路是减少用户态和内核态的上下文切换以及减少数据拷贝。
  • 我们知道上下文切换其实是由于系统调用产生,因此减少系统调用就可以减少上下文切换。同时在文件传输场景中,我们用户进程并不会对数据进行加工,那么我们是不是可以不用将数据拷贝到用户空间呢?答案是可以,因此文件传输下,用户缓冲区没有存在的必要。

零拷贝技术

  • 基于上述两点优化,发展出来了零拷贝技术,零拷贝技术一般有以下两种实现方案,下面我们就具体谈一谈它如何减少上下文切换和数据拷贝次数:
mmap + write
sendfile

mmap + write

  • 在传统的文件 IO 过程中,我们需要使用 read 调用将内核缓冲区的数据读到用户缓存区,为了减少这一步的复制开销,我们使用 mmap() 代替 read():
buf = mmap(file, len);
write(sockfd, buf, len);

  • 用户进程调用 mmap() 方法后,DMA 将数据从磁盘拷贝到内核缓冲区,用户进程和内核共享这个缓冲区。
  • 用户进程调用 read() 方法后,CPU 将数据从内核缓冲区拷贝到 Socket 缓冲区。

sendfile

  • 上面整个过程虽然减少了 2 次数据拷贝,但仍然存在 4 次上下文切换。
  • 在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile(),函数形式如下,可以进一步减少系统调用:
#include <sys/socket.h>
// 前两个参数分别是目的端和源端的文件描述符,后面两个参数是源端的偏移量和复制数据的长度,返回值是实际复制数据的长度
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

企业微信截图_16924179656803.png

  • 这样,我们一次文件传输,只需要 3 次数据拷贝和 2 次上下文切换。
SG-DMA(The Scatter-Gather Direct Memory Access)
  • 如果网卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术(和普通的 DMA 有所不同),sendfile() 调用还会进一步优化,去掉了 CPU 把内核缓冲区里的数据拷贝到 socket 缓冲区的过程,将数据直接从内核缓冲区拷贝到网卡中。

企业微信截图_16924183044145.png

  • 这就是真正的零拷贝技术(zero-copy),因为我们全程没有使用 CPU 拷贝数据,而是通过 DMA 来进行传输。

零拷贝技术的应用

  • 我们比较常用的 kafka 就使用了零拷贝技术,从而大幅提高了 I/O 的吞吐率,这也是 kafka 能处理海量数据的原因之一。
  • kafka 传输部分实现底层调用 Java NIO 库里的 transferTo 方法,如果 Linux 系统支持 sendfile() 系统调用,那么 transferTo() 实际上最后就会使用到 sendfile() 系统调用函数。
@Overridepublic 
long transferFrom(FileChannel fileChannel, long position, long count) throws IOException { 
    return fileChannel.transferTo(position, count, socketChannel);
}
  • 在同样的硬件条件下,传统文件传输和零拷拷贝文件传输的性能差异测试,使用了零拷贝技术接近缩短了 65% 的时间,能够大幅提升我们的吞吐量:
    零拷贝测试数据.png

大文件传输应该用什么方式

  • 在了解这个问题前,我们先了解两个概念 PageCache 和 直接 I/O。

PageCache(内核缓冲区) 的作用

  • Write Buffer:写入数据时内核 I/O 算法会尽可能缓存更多的 I/O 请求在 PageCahe 中,最后合并为一个更大的 I/O 请求给磁盘,减少磁盘的寻址操作。
  • Read Cache:内核会预读相邻的数据内容并缓存一些热点数据在 PageCahe 中,减少对磁盘的访问,提到访问速度。

直接 I/O

企业微信截图_16924185437690.png

直接 I/O 适用场景

  • 应用本身已经实现了磁盘数据缓存,那么就可以不需要 PageCahe ,减少内核缓冲区的复制带来的消耗。比如在 MySQL 数据库中就可以开启直接 I/O,默认不开启。
  • 数据本身过大,难以命中 PageCahe 缓存,同时会占满 PageCahe,导致其它热点数据失效,带来额外的性能开销。

综上所述

  • 从上面两点我们可以看出:
  • 对于小文件传输,我们可以使用零拷贝技术减少上下文的切换和数据拷贝次数提高性能。
疑问:小文件是否可以直接走用户缓存区不使用内核缓存区
答:
1、使用内核缓冲区 当从磁盘缓冲区拷贝数据可以使用 DMA
2、数据到达用户缓存区,理论上比数据到内核缓冲区的代价更大
  • 但对于大文件,已经不适合使用基于 PageCahe 的零拷贝技术,而是应该使用直接 I/O 的方式,同时为了避免大文件直接 I/O 带来的长时间阻塞,我们可以使用 直接 I/O + 异步 I/O 的方式传输大文件。

Nginx 中的零拷贝技术和直接 I/O

  • 在 nginx 中,既支持 零拷贝技术,也支持 直接 I/O 我们可以根据文件大小这样配置:
location /file/ { 
    sendfile on; 
    aio on; 
    directio 1024m; 
}
  • 当文件大小小于 1024M 时使用零拷贝技术,当大于时使用直接 IO 技术。

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第二百九十二回

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何混合选择图片和视频文件"相关的内容&#xff0c;本章回中将介绍如何混合选择多个图片和视频文件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1…

OpenGL/C++_学习笔记(四)空间概念与摄像头

汇总页 上一篇: OpenGL/C_学习笔记&#xff08;三&#xff09; 绘制第一个图形 OpenGL/C_学习笔记&#xff08;四&#xff09;空间概念与摄像头 空间概念与摄像头前置科技树: 线性代数空间概念流程简述各空间相关概念详述 空间概念与摄像头 前置科技树: 线性代数 矩阵/向量定…

毕业设计过程学习

传统的目标检测算法主要通过人工设计与纹理、颜色和形状相关的特征来进行目标区域特征的提取。随着深度学习和人工智能技术的飞速发展&#xff0c;目标检测技术也取得了很大的成就。早期基于深度学习的目标检测算法的研究方向仍然是将目标定位任务和图像分类任务分离开来的&…

1 月 27日算法练习-贪心

文章目录 扫地机器人分糖果最小战斗力差距谈判纪念品分组 扫地机器人 思路&#xff1a; 最优机器人清理方法&#xff1a;机器人清理方法先扫左边&#xff0c;有时间再扫右边。最短时间&#xff1a;通过枚举&#xff0c;从 1 开始&#xff0c;清理面积会越大直到全部面积的清理…

深入理解C语言(3):自定义类型详解

文章主题&#xff1a;结构体类型详解&#x1f30f;所属专栏&#xff1a;深入理解C语言&#x1f4d4;作者简介&#xff1a;更新有关深入理解C语言知识的博主一枚&#xff0c;记录分享自己对C语言的深入解读。&#x1f606;个人主页&#xff1a;[₽]的个人主页&#x1f3c4;&…

事务:分布式事务与本地事务的区别

分布式事务章节 分布式事务&#xff1a;2PC与3PC的区别-CSDN博客 分布式事务&#xff1a;X/Open DTP分布式事务处理模型与分布式事务处理XA规范-CSDN博客 事务简介 事务(Transaction)是操作数据库中某个数据项的一个程序执行单元(unit)。事务是由一组操作构成的可靠的独立的…

[SWPUCTF 2018]SimplePHP1

打开环境 有查看文件跟上传文件&#xff0c;查看文件里面显示没有文件url貌似可以文件读取 上传文件里面可以上传文件。 先看一下可不可以文件读取 /etc/passwd不能读取&#xff0c;源码提示flag在f1ag.php 看看能不能读取当前的文件&#xff0c; 先把代码摘下来 file.php …

LPC系列一个定时器不同频率

1.背景 最近研究的LPC804里只有一个ctimer&#xff0c;很多时候用的捉襟见肘的&#xff0c;官方给了一份双匹配的参考例程&#xff0c;不过实际用处不大。不过我花了一晚上的时间&#xff0c;终于研究出来将一个定时器拆成四个定时器用的办法了。这个方法适用于用回调函数的LP…

Fastbee物联网项目新手快速入门

一&#xff0c;前提条件 后端环境准备如下&#xff1a; 正式环境推荐硬件资源最低要求4c8G&#xff0c;硬盘40G。JDK 1.8.0_2xx (需要小版本号大于200) 。Maven3.6.3。&#xff08;IDEA启动时使用IDEA默认自带的版本即可&#xff09;。 启动fastbee之前&#xff0c;请先确定…

go语言(十七)----json

1、结构体转json package mainimport ("encoding/json""fmt" )type Movie struct{Title string json:"title"Year int json:"year"Price int json:"rmb"Actors []string json:"actors" }func main() {movie : Mo…

《A++ 敏捷开发》- 6 估算软件规模

为什么要估规模 规模可以帮我们&#xff1a; 依据历史数据策划&#xff0c;例如估算工作量、工期。归一(Normalize)不同项目作比较。知道现在水平。 依据历史数据策划先把项目分成组件&#xff0c;参考以往类似的组件所花工作量&#xff0c;估算整个项目的总工作量。规模大小…

Spring框架-AOP底层实现原理

文章目录 AOP底层实现原理AOP实现原理分析Java设计模式&#xff08;代理模式&#xff09;静态代理JDK动态代理CGLIB动态代理 AOP操作术语 AOP底层实现原理 AOP实现原理分析 1、AOP采取横向抽取机制&#xff0c;取代传统的纵向抽取机制&#xff08;继承关系&#xff09;。 2、…

腾讯云一键部署搭建幻兽帕鲁联机服务器教程

幻兽帕鲁&#xff08;Palworld&#xff09;是一款多人在线游戏&#xff0c;为了获得更好的游戏体验&#xff0c;许多玩家选择自行搭建游戏联机服务器&#xff0c;但是如何搭建游戏联机服务器成为一个难题&#xff0c;腾讯云提供了游戏联机服务器一键部署方案&#xff0c;让大家…

Java笔记 --- 五、File

五、File 概述 将字符串变成File对象&#xff0c;再去使用里面的方法 父级路径&#xff1a;除了文件本身的路径 C:\Users\Desktop 子级路径&#xff1a;文件名 m.txt 常见的成员方法 判断、返回 length 只能获取文件的大小(字节数量) 创建、删除 delete方法默认只能删除…

搜索<2>——记忆化搜索与剪枝

Part 1:记忆化搜索 记忆化搜索其实就是拿个数组记录下已经得到的值&#xff0c;这样再遇到的时候直接调用即可。 P1464: 虽然此题好像不用记忆化也行&#xff0c;但我们还是老老实实写个记忆化吧。没什么困难的地方&#xff0c;就是它叫你怎么干你就怎么干&#xff0c;记得开…

【Java 数据结构】栈和队列

栈和队列 1. 栈(Stack)1.1 概念1.2 栈的使用1.3 栈的模拟实现1.4 栈的应用场景1.5 概念区分 2. 队列(Queue)2.1 概念2.2 队列的使用2.3 队列模拟实现2.4 循环队列 3. 双端队列 (Deque)4. 面试题 1. 栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在…

Cyberdog2 docker环境软件源无法被验证问题

搭建docker系统后更新软件源sudo apt-get update出现异常 经过查询GPT&#xff0c;使用如下方式成功解决 从keyserver.ubuntu.com获取缺失的公钥&#xff0c;并添加到apt-key中。具体命令如下&#xff1a; gpg --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C6…

怎么把文章变成视频?原来这么简单

大家有没有发现&#xff0c;在各个平台浏览文章的时候总会发现很多图文相结合的长篇文章&#xff0c;对于不喜欢看长图文的人来说&#xff0c;长篇的图文会带来很多的负担&#xff0c;于是就有很多人想要把长篇的图文转换成视频&#xff0c;那么该如何转换呢&#xff1f; 首先&…

CMake简明教程 笔记

推荐B站视频&#xff1a;1.1 Cmake构建项目的流程_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1xa4y1R7vT?p1&vd_sourcea934d7fc6f47698a29dac90a922ba5a3 >>目录 1&#xff09;CMake初体验 CMake构建流程Windows下使用CMake构建项目Linux下使用CMake构…

C#,数据检索算法之插值搜索(Interpolation Search)的源代码

数据检索算法是指从数据集合&#xff08;数组、表、哈希表等&#xff09;中检索指定的数据项。 数据检索算法是所有算法的基础算法之一。 本文提供插值搜索&#xff08;Interpolation Search&#xff09;的源代码。 1 文本格式 using System; namespace Legalsoft.Truffer.…