0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一般会如何实现文件传输?零拷贝如何提升文件传输性能?

马哥Linux运维 来源:-零 2023-07-26 14:43 次阅读

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

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

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

31d4e830-29ef-11ee-a368-dac502259ad0.png

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

上下文切换:

首先,它至少经历了 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 次内存拷贝。

31e0706a-29ef-11ee-a368-dac502259ad0.jpg

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

31e98cfe-29ef-11ee-a368-dac502259ad0.jpg

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

它是操作系统提供的新函数,同时接收文件描述符和 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 方法会在磁盘寻址过程中阻塞等待,导致进程无法并发地处理其他任务,如下图所示:

31f3f6d0-29ef-11ee-a368-dac502259ad0.jpg

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

31fcb78e-29ef-11ee-a368-dac502259ad0.jpg

从图中可以看到,异步 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 指令)。

链接:https://www.cnblogs.com/-wenli/p/13380616.html





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编码器
    +关注

    关注

    45

    文章

    3584

    浏览量

    134105
  • dma
    dma
    +关注

    关注

    3

    文章

    559

    浏览量

    100411
  • 数据交换
    +关注

    关注

    0

    文章

    100

    浏览量

    17917
  • cache技术
    +关注

    关注

    0

    文章

    41

    浏览量

    1047
  • TCP通信
    +关注

    关注

    0

    文章

    146

    浏览量

    4215

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

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何高效实现文件传输

    服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。如果需要你自己编码实现这个文件传输功能,你怎么
    发表于 08-01 16:16 513次阅读
    如何高效<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b>

    关于基于labview的文件传输

    本帖最后由 eehome 于 2013-1-5 10:02 编辑 利用labview的datasocket的相关知识,能实现些字符串从个 文本文件传输到另
    发表于 05-05 00:42

    文件传输解决方案

    文件传输个通用术语,适用于通过计算机网络传输数据的行为,私有或公共。托管文件传输旨在促进文件传输,它是
    发表于 07-18 07:34

    Linux的文件传输

    Linux之文件传输
    发表于 05-26 09:01

    WinSCP文件传输工具分享

    WinSCP文件传输工具win和树莓派下方便的数据传输软件
    发表于 10-07 08:46

    基于线程池技术的文件传输模型的改进

    本文首先就涉及的文件传输模型和线程池技术作了分析,在考虑了文件传输的特点后,结合线程池技术来对原来的文件传输模型提出了种改进方案,从而提高了传输
    发表于 06-18 09:18 15次下载

    网络文件传输源代码

    易语言是门以中文作为程序代码编程语言学习例程:易语言-网络文件传输
    发表于 06-06 17:36 4次下载

    易语言-文件传输

    易语言是门以中文作为程序代码编程语言学习例程:易语言-文件传输
    发表于 06-06 17:43 5次下载

    实现CFDP协议延时NAK模式文件传输

    当前我国星上数据组织管理采用位流的形式,数据的下行传输没有实现保证数据可靠性的机制,所有数据按比特流顺序传输完成即结束,无法保证文件的有效性与完整性。空间数据系统咨询委员
    发表于 11-05 11:33 2次下载
    <b class='flag-5'>实现</b>CFDP协议延时NAK模式<b class='flag-5'>文件传输</b>

    基于打包策略的文件传输策略

    基于互联网的文件传输策略将直接影响到文件传输效率和网络资源的使用效率,这情况在各种资源集中的云计算环境表现得更为明显,特别是当传输大量小文件
    发表于 12-06 14:06 1次下载

    WinSCP文件传输工具应用程序免费下载

    本文档的主要内容详细介绍的是WinSCP文件传输工具应用程序免费下载。
    发表于 03-27 09:48 10次下载

    基于openharmony适配移植的web端与app端文件传输教程

    项目介绍 项目名称:文件传输 所属系列:openharmony的第三方组件适配移植 功能:web端与app端文件传输 项目移植状态:完成 调用差异:因网络库限制 暂不支持断点续传功能以及文件传输速度
    发表于 04-12 09:45 1次下载

    基于UDP的简单文件传输协议TFTP设计

    前面我们已经实现了UDP的回环客户端和回环服务器的简单应用,接下来我们实现个基于UDP的简单文件传输协议TFTP。
    的头像 发表于 12-14 15:06 2384次阅读
    基于UDP的简单<b class='flag-5'>文件传输</b>协议TFTP设计

    文件管理器与文件传输的操作方法

    AnyDesk安力桌为在本地和远程端点之间文件传输,提供各种选项。这可以通过 "文件管理器"会话或通过远程控制会话中的 "文件传输 "完成。
    的头像 发表于 08-30 11:04 1447次阅读

    如何实现文件传输

    如何实现文件传输? 服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。如果需要你自己编码
    的头像 发表于 11-13 15:32 896次阅读
    如何<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b>