如何高效实现文件传输:小文件采用零拷贝、大文件采用异步io+直接io

news2024/11/27 4:28:53

一般会如何实现文件传输?

服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。如果需要你自己编码实现这个文件传输功能,你会怎么实现呢?

通常,你会选择最直接的方法:从网络请求中找出文件在磁盘中的路径后,如果这个文件比较大,假设有 320MB,可以在内存中分配 32KB 的缓冲区,再把文件分成一万份,每份只有 32KB,这样,从文件的起始位置读入 32KB 到缓冲区,再通过网络 API 把这 32KB 发送到客户端。接着重复一万次,直到把完整的文件都发送完毕。如下图所示:

​不过这个方案性能并不好,主要有两个原因。

上下文切换:

首先,它至少经历了 4 万次用户态与内核态的上下文切换。因为每处理 32KB 的消息,就需要一次 read 调用和一次 write 调用,每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态。可见,每处理 32KB,就有 4 次上下文切换,重复 1 万次后就有 4 万次切换。

上下文切换的成本并不小,虽然一次切换仅消耗几十纳秒到几微秒,但高并发服务会放大这类时间的消耗。

内存拷贝:

其次,这个方案做了 4 万次内存拷贝,对 320MB 文件拷贝的字节数也翻了 4 倍,到了 1280MB。很显然,过多的内存拷贝无谓地消耗了 CPU 资源,降低了系统的并发处理能力。

所以要想提升传输文件的性能,需要从降低上下文切换的频率和内存拷贝次数两个方向入手。

零拷贝如何提升文件传输性能?

首先,我们来看如何降低上下文切换的频率。

为什么读取磁盘文件时,一定要做上下文切换呢?这是因为,读取磁盘或者操作网卡都由操作系统内核完成。内核负责管理系统上的所有进程,它的权限最高,工作环境与用户进程完全不同。只要我们的代码执行 read 或者 write 这样的系统调用,一定会发生 2 次上下文切换:首先从用户态切换到内核态,当内核执行完任务后,再切换回用户态交由进程代码执行。

因此,如果想减少上下文切换次数,就一定要减少系统调用的次数。解决方案就是把 read、write 两次系统调用合并成一次,在内核中完成磁盘与网卡的数据交换。

其次,我们应该考虑如何减少内存拷贝次数。

每周期中的 4 次内存拷贝,其中与物理设备相关的 2 次拷贝是必不可少的,包括:把磁盘内容拷贝到内存,以及把内存拷贝到网卡。但另外 2 次与用户缓冲区相关的拷贝动作都不是必需的,因为在把磁盘文件发到网络的场景中,用户缓冲区没有必须存在的理由。

如果内核在读取文件后,直接把 PageCache 中的内容拷贝到 Socket 缓冲区,待到网卡发送完毕后,再通知进程,这样就只有 2 次上下文切换,和 3 次内存拷贝。

​如果网卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术,还可以再去除 Socket 缓冲区的拷贝,这样一共只有 2 次内存拷贝。

​实际上,这就是零拷贝技术。

相关视频推荐

手写用户态协议栈以及零拷贝的实现

服务器性能优化,异步处理有哪些不一样的

用户态网络缓冲区设计-ringbuffer、chainbuffer

免费学习地址:c/c++ linux服务器开发/后台架构师

需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

​它是操作系统提供的新函数,同时接收文件描述符和 TCP socket 作为输入参数,这样执行时就可以不需要用户层缓存,完全在内核态完成内存拷贝,既减少了内存拷贝次数,也降低了上下文切换次数。

而且,零拷贝取消了用户缓冲区后,不只降低了用户内存的消耗,还通过最大化利用 socket 缓冲区中的内存,间接地再一次减少了系统调用的次数,从而带来了大幅减少上下文切换次数的机会!

你可以回忆下,没用零拷贝时,为了传输 320MB 的文件,在用户缓冲区分配了 32KB 的内存,把文件分成 1 万份传送,然而,这 32KB 是怎么来的?为什么不是 32MB 或者 32 字节呢?这是因为,在没有零拷贝的情况下,我们希望内存的利用率最高。如果用户缓冲区过大,它就无法一次性把消息全拷贝给 socket 缓冲区;如果用户缓冲区过小,则会导致过多的 read/write 系统调用。

那用户缓冲区为什么不与 socket 缓冲区大小一致呢?这是因为,socket 缓冲区的可用空间是动态变化的,它既用于 TCP 滑动窗口,也用于应用缓冲区,还受到整个系统内存的影响。尤其在长肥网络中,它的变化范围特别大。

零拷贝使我们不必关心 socket 缓冲区的大小。比如,调用零拷贝发送方法时,尽可以把发送字节数设为文件的所有未发送字节数,例如 320MB,也许此时 socket 缓冲区大小为 1.4MB,那么一次性就会发送 1.4MB 到客户端,而不是只有 32KB。这意味着对于 1.4MB 的 1 次零拷贝,仅带来 2 次上下文切换,而不使用零拷贝且用户缓冲区为 32KB 时,经历了 176 次(4 * 1.4MB/32KB)上下文切换。

综合上述各种优点,零拷贝可以把性能提升至少一倍以上!对文章开头提到的 320MB 文件的传输,当 socket 缓冲区在 1.4MB 左右时,只需要 4 百多次上下文切换,以及 4 百多次内存拷贝,拷贝的数据量也仅有 640MB,这样,不只请求时延会降低,处理每个请求消耗的 CPU 资源也会更少,从而支持更多的并发请求。

此外,零拷贝还使用了 PageCache 技术,通过它,零拷贝可以进一步提升性能,我们接下来看看 PageCache 是如何做到这一点的。

PageCache,磁盘高速缓存

回顾上文中的几张图,你会发现,读取文件时,是先把磁盘文件拷贝到 PageCache 上,再拷贝到进程中。为什么这样做呢?有两个原因所致。

第一,由于磁盘比内存的速度慢许多,所以我们应该想办法把读写磁盘替换成读写内存,比如把磁盘中的数据复制到内存中,就可以用读内存替换读磁盘。但是,内存空间远比磁盘要小,内存中注定只能复制一小部分磁盘中的数据。

选择哪些数据复制到内存呢?通常,刚被访问的数据在短时间内再次被访问的概率很高(这也叫“时间局部性”原理),用 PageCache 缓存最近访问的数据,当空间不足时淘汰最久未被访问的缓存(即 LRU 算法)。读磁盘时优先到 PageCache 中找一找,如果数据存在便直接返回,这便大大提升了读磁盘的性能。

第二,读取磁盘数据时,需要先找到数据所在的位置,对于机械磁盘来说,就是旋转磁头到数据所在的扇区,再开始顺序读取数据。其中,旋转磁头耗时很长,为了降低它的影响,PageCache 使用了预读功能。

也就是说,虽然 read 方法只读取了 0-32KB 的字节,但内核会把其后的 32-64KB 也读取到 PageCache,这后 32KB 读取的成本很低。如果在 32-64KB 淘汰出 PageCache 前,进程读取到它了,收益就非常大。这一讲的传输文件场景中这是必然发生的。

从这两点可以看到 PageCache 的优点,它在 90% 以上场景下都会提升磁盘性能,但在某些情况下,PageCache 会不起作用,甚至由于多做了一次内存拷贝,造成性能的降低。在这些场景中,使用了 PageCache 的零拷贝也会损失性能。

具体是什么场景呢?就是在传输大文件的时候。比如,你有很多 GB 级的文件需要传输,每当用户访问这些大文件时,内核就会把它们载入到 PageCache 中,这些大文件很快会把有限的 PageCache 占满。

然而,由于文件太大,文件中某一部分内容被再次访问到的概率其实非常低。这带来了 2 个问题:首先,由于 PageCache 长期被大文件占据,热点小文件就无法充分使用 PageCache,它们读起来变慢了;其次,PageCache 中的大文件没有享受到缓存的好处,但却耗费 CPU 多拷贝到 PageCache 一次。

所以,高并发场景下,为了防止 PageCache 被大文件占满后不再对小文件产生作用,大文件不应使用 PageCache,进而也不应使用零拷贝技术处理。

异步 IO + 直接 IO

高并发场景处理大文件时,应当使用异步 IO 和直接 IO 来替换零拷贝技术。

仍然回到本讲开头的例子,当调用 read 方法读取文件时,实际上 read 方法会在磁盘寻址过程中阻塞等待,导致进程无法并发地处理其他任务,如下图所示:

​异步 IO(异步 IO 既可以处理网络 IO,也可以处理磁盘 IO,这里我们只关注磁盘 IO)可以解决阻塞问题。它把读操作分为两部分,前半部分向内核发起读请求,但不等待数据就位就立刻返回,此时进程可以并发地处理其他任务。当内核将磁盘中的数据拷贝到进程缓冲区后,进程将接收到内核的通知,再去处理数据,这是异步 IO 的后半部分。如下图所示:

​从图中可以看到,异步 IO 并没有拷贝到 PageCache 中,这其实是异步 IO 实现上的缺陷。经过 PageCache 的 IO 我们称为缓存 IO,它与虚拟内存系统耦合太紧,导致异步 IO 从诞生起到现在都不支持缓存 IO。

绕过 PageCache 的 IO 是个新物种,我们把它称为直接 IO。对于磁盘,异步 IO 只支持直接 IO。

直接 IO 的应用场景并不多,主要有两种:第一,应用程序已经实现了磁盘文件的缓存,不需要 PageCache 再次缓存,引发额外的性能消耗。比如 MySQL 等数据库就使用直接 IO;第二,高并发下传输大文件,我们上文提到过,大文件难以命中 PageCache 缓存,又带来额外的内存拷贝,同时还挤占了小文件使用 PageCache 时需要的内存,因此,这时应该使用直接 IO。

当然,直接 IO 也有一定的缺点。除了缓存外,内核(IO 调度算法)会试图缓存尽量多的连续 IO 在 PageCache 中,最后合并成一个更大的 IO 再发给磁盘,这样可以减少磁盘的寻址操作;另外,内核也会预读后续的 IO 放在 PageCache 中,减少磁盘操作。直接 IO 绕过了 PageCache,所以无法享受这些性能提升。

有了直接 IO 后,异步 IO 就可以无阻塞地读取文件了。现在,大文件由异步 IO 和直接 IO 处理,小文件则交由零拷贝处理,至于判断文件大小的阈值可以灵活配置(参见 Nginx 的 directio 指令)。

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

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

相关文章

嵌入式学习_Day 003

程序功能介绍 c #include <stdio.h> int main() {char c,ll;printf("please enter a capital letter:");cgetchar();getchar();if (c>A&& c<Z) {llc32;printf("Lowercase letter output:%c\n",ll);printf("ASCII value:%d\n"…

阿含经人物传记知识图谱与问答系统设计20230725(进行中)

基本思路—— 1 数据提取 以《房山石经》阿含经为核心&#xff0c;提取经文索引、内容、关键词等数据&#xff0c;构成excel数据&#xff1b; 2 数据清洗 从数据库中重新建构角色画像数据&#xff0c;形成佛、辟支佛、尊者、比丘、比丘尼……等各类人物数据 3 数据映射&…

缠论线段的划分

第一种情况&#xff1a; 第二种情况&#xff1a; 第二种情况中的特例&#xff1a; 第二种情况的特例&#xff1a; 顶分型成立&#xff1a; 向上线段延续&#xff1a; 顶分型后面底分型&#xff0c;形成三段 插入一个分型的反面例子&#xff1a; dd

软件测试外包公司怎么选?CMA/CNAS软件测试报告的优势

在当前信息化和全球化的背景下&#xff0c;软件测试外包公司是很多企业选择的一种方式。因为软件测试外包公司具备丰富的专业能力和经验&#xff0c;能够提供高质量的测试服务。同时&#xff0c;外包公司可以根据客户需求灵活组织测试团队&#xff0c;并且能够及时响应和处理问…

微信怎么批量删除好友?

今天我们来说说微信怎么批量删除好友。 为什么会想要说这个呢&#xff0c;原因是我有一个朋友离职后发朋友圈求助说离职后怎么把前同事们都删除。在日常使用微信中&#xff0c;相信也有些朋友对于一些毫不相关的好友想要删除掉。 一般的做法都是一个一个删除&#xff0c;但很繁…

上位机软件wincc通过工业网关采集plc数据实现组态监控

WinCC是一个组态软件&#xff0c;可以用于数据采集与监控、自动化控制、工业物联网等领域。WinCC可以帮助用户实现工厂自动化和过程自动化的解决方案&#xff0c;提供可视化的监控界面和数据采集分析功能&#xff0c;支持多种协议和设备&#xff0c;如Siemens、Modbus、OPC等。…

数据库应用:Redis持久化

目录 一、理论 1.Redis 高可用 2.Redis持久化 3.RDB持久化 4.AOF持久化&#xff08;支持秒级写入&#xff09; 5.RDB和AOF的优缺点 6.RDB和AOF对比 7.Redis性能管理 8.Redis的优化 二、实验 1.RDB持久化 2.AOF持久化 3.Redis性能管理 4.Redis的优化 三、总结 一、…

C# 数据结构】Heap 堆

【C# 数据结构】Heap 堆 先看看C#中有那些常用的结构堆的介绍完全二叉树最大堆 Heap对类进行排序实现 IComparable<T> 接口 对CompareTo的一点解释 参考资料 先看看C#中有那些常用的结构 作为 数据结构系类文章 的开篇文章&#xff0c;我们先了解一下C# 有哪些常用的数据…

进入元宇宙,半岛体育打开新世界大门

上赛季西甲联赛在新赛季开启之际,宣布与科技公司Stadio Plus合作,计划在元宇宙平台Decentraland的Vegas City打造西甲主题地块,与Z世代球迷更好地互动,这进一步推高了外界对于“体育元宇宙”的关注。伴随着AR/VR、云计算、AI等技术的日益成熟,叠加后疫情因素的影响,从源头的训练…

K8S:容器日志收集与管理

Kubernetes 里面对容器日志的处理方式&#xff0c;都叫作 cluster-level-logging&#xff0c;即&#xff1a;这个日志处理系统&#xff0c;与容器、Pod 以及 Node 的生命周期都是完全无关的。这种设计当然是为了保证&#xff0c;无论是容器挂了、Pod 被删除&#xff0c;甚至节点…

Linux_CentOS_7.9部署Docker以及镜像加速配置等实操验证全过程手册

前言&#xff1a;实操之前大家应该熟悉一个新的名词DevOps 俗称开发即运维、新一代开发工程师&#xff08;Development和Operations的组合词&#xff09;是一组过程、方法与系统的统称&#xff0c;用于促进开发&#xff08;应用程序/软件工程&#xff09;、技术运营和质量保障&…

【*1800树上贪心】CF1401 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 首先&#xff0c;1尽可能少&#xff0c;那就是让pi尽可能不合并地摊到所有边上&#xff0c;然后计算贡献 按照CF惯用套路&#xff0c;这样的n^2贡献肯定是更换枚举对象&#xff0c;我们去枚举边&#xff0c;按边…

Docker consul 的容器服务更新与发现

目录 一、Consul 简介 1.什么是服务注册与发现 2. 什么是consul 3.consul 架构 二、部署 consul 服务器&#xff08;192.168.88.10&#xff09; 1.建立 Consul 服务 2.查看集群信息 3.通过 http api 获取集群信息 三、registrator服务器&#xff08;192.168.88.60&…

Gnomon水下环境 下

不会全下去 鱼群 方向反了&#xff0c;位置不对 不动了 速度快&#xff0c;一个条 数量太多 太卡 使用的弧线没问题 &#xff0c;这块我有点晕 水泡制作 运动严重 减少晃动 turbulenceField1.phaseZ time*20; 总结 使用晶格调节大概样子,变成柔体 particleShape1.daxiaorand(…

shell实现数据库分库分表备份

#!/bin/bash2 3 backup/backup/db #存放数据库的位置4 nodatabasesinformation_schema|mycat|performance_schema|sys|mysql #要过滤的数据库5 6 mysql -uroot -predhat -e "show databases" -N | egrep -v "${nodatabases}" > dbname #将数据库存放在…

ansible自动化运维(二)剧本、角色编写实战

&#x1f618;作者简介&#xff1a;一名运维工作人员。 &#x1f44a;宣言&#xff1a;人生就是B&#xff08;birth&#xff09;和D&#xff08;death&#xff09;之间的C&#xff08;choise&#xff09;&#xff0c;做好每一个选择。 &#x1f64f;创作不易&#xff0c;动动小…

在C语言中,变量主要的作用是什么?

常量记忆数据只能存储一个固定的数据&#xff0c;永远不变&#xff0c;所以这当然不能算得上是记忆数据 变量存储的数据可以改变&#xff0c;你可以让它记忆5&#xff0c;下一步它可以变为10 如果你还无法理解 那么请不用尝试变量编程实现以下&#xff1a; 输入一个100之内…

Cesium态势标绘专题-简单箭头(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

NoSQL-Redis持久化

NoSQL-Redis持久化 一、Redis 高可用&#xff1a;1.概述&#xff1a; 二、Redis持久化&#xff1a;1.持久化的功能&#xff1a;2.Redis 提供两种方式进行持久化&#xff1a; 三、RDB 持久化&#xff1a;1.定义&#xff1a;2.触发条件&#xff1a;3.执行流程&#xff1a;4.启动时…

地下水除砷工艺盘点:生物法、混凝法、沉淀法、吸附法和离子交换法

砷(As)为非人体必需元素&#xff0c;既不溶解于水又不溶解于酸&#xff0c;在自然界有三价无机态 As(III)、五价无机态 As(V)以及有机砷MMA(甲基胂酸)、DMA(二甲基胂酸)、TMA(三甲基胂酸)等。 砷在水体中主要以三价和五价的无机酸形式存在&#xff0c;三价砷的毒性更强&#xf…