首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >何为真正的零拷贝

何为真正的零拷贝

作者头像
shysh95
发布于 2021-11-09 02:39:34
发布于 2021-11-09 02:39:34
89800
代码可运行
举报
文章被收录于专栏:shysh95shysh95
运行总次数:0
代码可运行

Hi~朋友,关注置顶防止错过消息

传统的文件传输有啥缺点?

传统IO的工作方式是,数据读取和写入是从用户空间和内核空间来回复制,内核空间的数据时通过操作系统层面的IO接口从磁盘读取或写入。

通过上图可以看出,在我们执行read和writer之间,一共发生了4次用户态和内核态上下文切换,在高并发的场景下,用户态和内核态上下文切换带来的性能消耗将会极大的降低系统的性能。

除了上下文的切换,在这个过程也一共发生了4次数据拷贝,其中包含两次DMA拷贝,两次CPU拷贝。

  • 第一次拷贝:借助DMA完成,把磁盘上的数据拷贝到内核的缓冲区里
  • 第二次拷贝:借助CPU完成,把内核缓冲区的数据拷贝到用户的缓冲区,以便应用程序可以操作这些数据
  • 第三次拷贝:把用户缓冲区数据再拷贝到内核中Sokcet的缓冲区中,需要借助CPU完成
  • 第四次拷贝:借助DMA完成,将内核Socket缓冲区中的数据拷贝到网卡的缓冲区中

可以看到我们在一个主机上如果想把某个文件的内容通过网络发送出去,将会进行4次切换和4次拷贝,但在这4次拷贝的过程中拷贝的都是同一份数据,过多的数据拷贝造成了系统性能的下降。

因此,为了优化文件的传输性能,我们需要减少上下切换和拷贝的次数。

如何实现零拷贝?

  • mmap + write
  • sendfile

mmap + write

read()系统调用会把内核缓冲区的内容拷贝到用户空间,为了减少这一次的拷贝,我们使用mmap()系统调用替换掉read()

mmap函数会直接把内核缓冲区的数据映射到用户空间,这样操作系统内核和用户空间就不需要再进行数据的拷贝。

  • 应用进程调用mmap函数以后,DMA会把磁盘的数据拷贝到内核缓冲区里,接着应用程序会和操作系统内核共享这个缓冲区
  • 应用进程再调用write函数,操作系统直接将内核中的数据拷贝到Socket缓冲区,这一步需要借助CPU
  • 最后再借助DMA将Socket缓冲区的数据拷贝到网卡缓冲区里

mmap + write的实现方式需要3次数据拷贝和4次上下文切换

sendfile

sendfile是Linux内核2.1版本中专门发送文件的系统调用函数,函数形式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
  • out_fd:目的端文件描述符
  • in_fd:源端文件描述符
  • offset:源端的偏移量
  • count:复制数据的长度
  • ssize_t:返回参数,实际复制数据的长度

sendfile可以替代read()和write()这两个系统调用,因此系统调用从2次变为1次,相应的上下文切换也会变为2次。

其次,sendfile可以直接把内核缓冲区的数据拷贝到Socket缓冲区,因此通过sendfile函数,我们可以将上下文切换减少为2次,数据拷贝3次。

如何实现真正的零拷贝?

上述零拷贝还不是真正的零拷贝,如果网卡支持SG-DMA技术的话,我们可以进一步减少数据拷贝的次数(即减少CPU把内核缓冲区的内容拷贝到Socket缓冲区的过程)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ ethtool -k eth0 | grep scatter-gather

上述命令可以查看网卡是否支持SG-DMA技术。

在Linux内核2.4y以后,对于网卡支持SG-DMA技术的情况下,sendfile系统调用的过程也发生了变化:

  1. 首先通过DMA拷贝将磁盘的数据拷贝到内核缓冲区
  2. 第二步,将缓冲区描述符和数据长度传到Socket缓冲区,网卡的SG-DMA控制器可以直接将内核缓冲区的数据拷贝到网卡的缓冲区里

通过以上技术,我们真正实现了零拷贝,数据拷贝次数发生两次,并且我们全程没有让CPU介入数据拷贝过程,通过DMA技术实现了数据的拷贝。总体来看,零拷贝技术可以把文件性能至少提高一倍以上。

PageCache是什么?

在我们上面一直提到一个内核缓冲区,该内核缓冲区就是PageCache(磁盘高速缓存)。

PageCache的优点?

  • PageCache存在于内存中,读写内存速度远远快于读写磁盘速度
  • 根据程序局部性规则,刚刚访问的数据在短时间内被访问的概率很高,因此PageCache缓存了最近被访问的数据,当读磁盘数据时,优先在PageCache中查找,如果数据存在可以直接返回,如果没有就需要从磁盘中读取,当空间不足时需要淘汰最久未被访问的缓存
  • PageCache使用了预读功能,比如read方法每次只读取32kb,但内核实际上会将后面的32kb-64kb的内容也读取到PageCache,这样对于读取后续的数据成本就会变低

PageCache的缺点?

  • 不适合传输大文件(GB级别),在传输大文件时,PageCache会失效,也就是说DMA的数据拷贝是一次多余的操作。
  • PageCache如果长时间被大文件占据,热点的小文件就无法使用到PageCache

所以针对大文件的传输,不应该使用零拷贝技术。

如何解决大文件传输问题?

异步IO + 直接IO。

异步IO主要解决read方法调用时的阻塞问题,通过上图可以看出:

  • 在内核向磁盘发起读请求时,可以不等待数据就位就可以返回,此时进程依旧可以处理其他任务
  • 当磁盘中的数据拷贝到用户缓冲区时,进程将收到内核的通知,此时进程就可以去处理数据了

异步IO整个过程没有涉及到PageCache,绕开PageCache的IO也可以成为直接IO。通常对于磁盘来说,异步IO只支持直接IO。

所以在传输大文件时,可以使用异步IO+直接IO无阻塞的读取文件。

直接IO的使用场景?

  • 应用程序已经实现了磁盘数据的缓存,那么便不再需要PageCache了。在MySQL数据库中,可以通过参数开启直接IO
  • 传输大文件时,由于大文件无法命中PageCache缓存,因此也应该使用直接IO
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
原来 8 张图,就可以搞懂「零拷贝」了
磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝、直接 I/O、异步 I/O 等等,这些优化的目的就是为了提高系统的吞吐量,另外操作系统内核中的磁盘高速缓存区,可以有效的减少磁盘的访问次数。
帅地
2020/09/28
1.3K0
原来 8 张图,就可以搞懂「零拷贝」了
Linux零拷贝和Netty零拷贝
DMA 的全称叫直接存储器访问(Direct Memory Access),是一种允许外围设备(硬件子系统)直接访问系统主内存的机制。
leobhao
2023/03/11
2.9K0
Linux零拷贝和Netty零拷贝
DMA 和 零拷贝技术 到 网络大文件传输优化
👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.
Lorin 洛林
2024/01/27
1.1K2
DMA 和 零拷贝技术 到 网络大文件传输优化
从Linux零拷贝深入了解Linux I/O
存储器是计算机的核心部件之一,在完全理想的状态下,存储器应该要同时具备以下三种特性:
Kevinello
2022/11/28
2.6K0
从Linux零拷贝深入了解Linux I/O
零拷贝技术 与 sendfile
可以看到,整个数据的传输过程,都要需要 CPU 亲自参与搬运数据的过程,而且这个过程,CPU 是不能做其他事情的。
看、未来
2021/10/18
1.2K0
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
公众号《鲁大猿》 ,寻精品资料,帮你构建Java全栈知识体系 http://www.jiagoujishu.cn
鲁大猿
2024/01/05
4830
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
java 零拷贝_java深拷贝
在介绍零拷贝的IO模式之前,我们先简单了解下传统的IO模式是怎么样的?
全栈程序员站长
2022/11/08
9230
java 零拷贝_java深拷贝
面试系列之-rocketmq零拷贝原理
传统的WEB服务器在收到请求后,从磁盘读取数据,然后将数据写到网卡,通过网卡发送给客户端,这一读一写的过程中就涉及数据的拷贝:
用户4283147
2022/12/29
1.6K0
面试系列之-rocketmq零拷贝原理
如何实现零拷贝
零拷贝经常在各个框架使用,比如kafka,rocketmq,都起到了很好的作用,首先我们要知道零拷贝不是没有一次拷贝,是尽可能的减少拷贝。
小土豆Yuki
2022/12/01
6770
如何实现零拷贝
零拷贝技术:减少数据复制和上下文切换,提高网络传输效率(下)
在前一章节中,我们了解了DMA技术在文件传输中的重要性,并简要介绍了零拷贝技术。为了提高文件传输的性能,我们需要减少用户态与内核态之间的上下文切换次数以及内存拷贝次数。本章将深入探讨零拷贝技术的优化方法,让我们一起走进零拷贝的优化之路!
努力的小雨
2023/11/25
8130
从新手到架构师:Web服务器如何实现大文件跨节点传输
看过一个文章 HTTP 断点续传(分块传输)我了解, 但是让我按照他们做法 八股文说出,我不愿意,说不出口。
早起的鸟儿有虫吃
2025/06/28
850
从新手到架构师:Web服务器如何实现大文件跨节点传输
java 零拷贝
什么是零拷贝 维基上是这么描述零拷贝的:零拷贝描述的是CPU不执行拷贝数据从一个存储区域到另一个存储区域的任务,这通常用于通过网络传输一个文件时以减少CPU周期和内存带宽。
海涛
2020/06/08
1.2K0
java 零拷贝
看一遍就理解:零拷贝详解
零拷贝是老生常谈的问题啦,大厂非常喜欢问。比如Kafka为什么快,RocketMQ为什么快等,都涉及到零拷贝知识点。最近技术讨论群几个伙伴分享了阿里、虾皮的面试真题,也都涉及到零拷贝。因此本文将跟大家一起来学习零拷贝原理。
捡田螺的小男孩
2021/12/21
6.9K1
看一遍就理解:零拷贝详解
什么是零拷贝?
相信不少的网友,在很多的博客文章里面,已经见到过零拷贝这个词,会不禁的发出一些疑问,什么是零拷贝?
Java极客技术
2023/09/14
5010
什么是零拷贝?
框架篇:小白也能秒懂的Linux零拷贝原理
大白话解释,零拷贝就是没有把数据从一个存储区域拷贝到另一个存储区域。但是没有数据的复制,怎么可能实现数据的传输呢?其实我们在java NIO、netty、kafka遇到的零拷贝,并不是不复制数据,而是减少不必要的数据拷贝次数,从而提升代码性能
捡田螺的小男孩
2020/11/17
1K0
框架篇:小白也能秒懂的Linux零拷贝原理
【Linux内核】零拷贝技术
零拷贝(Zero-copy) 技术指在计算机执行操作时,CPU不需要先将数据从一个缓冲区复制到另一个缓冲区当中,也就是CPU不参与内存拷贝的过程,从而可以减少上下文切换以及CPU的拷贝时间。
用户11029129
2025/03/21
4160
【Linux内核】零拷贝技术
Linux零拷贝和Netty零拷贝
DMA 的全称叫直接内存存取(Direct Memory Access),是一种允许外围设备(硬件子系统)直接访问系统主内存的机制。
leobhao
2022/06/28
3.6K0
Linux零拷贝和Netty零拷贝
Kafka-为什么这么快(零拷贝Zero-Copy)
作者介绍:简历上没有一个精通的运维工程师,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。
运维小路
2025/06/07
1140
Kafka-为什么这么快(零拷贝Zero-Copy)
DMA与零拷贝
注意事项:除了 Direct I/O,与磁盘相关的文件读写操作都有使用到 page cache 技术。
运维部落
2021/09/22
2.5K0
DMA与零拷贝
零拷贝详解_深拷贝和浅拷贝如何实现
1、用户态与内核态 ⽤户态和内核态是操作系统的两种运⾏状态。 (1)内核态:处于内核态的CPU可以访问任意的数据,包括外围设备,⽐如⽹卡、硬盘等,处于内核态的 CPU 可以从⼀个程序切换到另外⼀个程序,并且占⽤ CPU 不会发⽣抢占情况,⼀般处于特权级 0 的状态我们称之为内核态。 (2)⽤户态:处于⽤户态的CPU只能受限的访问内存,并且不允许访问外围设备,⽤户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。
全栈程序员站长
2022/10/05
1.3K0
零拷贝详解_深拷贝和浅拷贝如何实现
相关推荐
原来 8 张图,就可以搞懂「零拷贝」了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档