首页 > 其他分享 >零拷贝技术:减少数据复制和上下文切换,提高网络传输效率(下)

零拷贝技术:减少数据复制和上下文切换,提高网络传输效率(下)

时间:2023-09-25 10:32:02浏览次数:38  
标签:DMA 传输 内核 缓冲区 拷贝 上下文 数据

前章回顾

在前一章节中,我们了解了DMA技术在文件传输中的重要性,并简要介绍了零拷贝技术。为了提高文件传输的性能,我们需要减少用户态与内核态之间的上下文切换次数以及内存拷贝次数。本章将深入探讨零拷贝技术的优化方法,让我们一起走进零拷贝的优化之路!

如何优化文件传输的性能?

当我们意识到有问题需要进行优化时,我们可以逐个解决问题,例如先减少用户态和内核态的上下文切换次数。

我们知道上下文切换是因为用户空间没有权限操作磁盘或网卡,而只能在虚拟空间上进行。相比之下,内核拥有最高权限,因此操作设备的任务都需要操作系统内核完成。为此,我们需要使用操作系统提供的系统调用函数来通过内核完成这些任务。如果对此还不清楚的小伙伴,可以查看之前章节中单独讲解的内容。

一次系统调用必然会发生两次上下文切换:首先从用户态切换到内核态,当内核执行完任务后,再切换回用户态由进程代码继续执行。

因此,要减少上下文切换的次数,就需要减少系统调用的次数。

另外,我们还可以减少数据拷贝的次数。在之前的分析中,我们发现操作会进行四次数据拷贝,包括两次CPU拷贝和两次DMA控制器数据拷贝。然而,在文件传输过程中,我们实际上并没有对文件进行任何操作,只是将磁盘文件传输给网卡。CPU数据拷贝的次数是由于上下文切换导致CPU在用户态和内核态之间来回复制数据,这是没有必要的。此外,用户缓冲区在整个传输过程中也是没有必要存在的。

如何实现零拷贝

零拷贝技术实现的方式通常有 2 种:

  1. mmap + write
  2. sendfile

让我们来探讨一下如何通过两种方式实现零拷贝技术,从而减少上下文切换和数据拷贝的次数。

mmap(共享缓冲区) + write

首先是使用 mmap + write 的方式。在之前的讨论中,我们了解到在使用 read() 系统调用时,会发生将内核缓冲区的数据拷贝到用户缓冲区的过程。为了减少这一步的开销,可以使用 mmap() 替换 read() 系统调用函数。

我们之前在讨论进程间如何通信时,我们有提到过共享缓冲区,即将内核态的一部分内存空间映射到应用程序所使用的虚拟空间上。如图所示:

image

而我们此时并不需要多个进程通信,如果只需要将物理内存映射给需要文件传输的进程,情况就会变得稍有不同。那么就可以演化成下面的这种方式,如图所示:

image

具体过程如下:

  1. 应用程序调用 mmap() 函数后,DMA会将磁盘数据拷贝到内核态的缓存区上,然后应用程序与操作系统共享这个缓冲区。
  2. 应用程序调用 write(),操作系统直接将内核态中的缓冲区数据拷贝到 socket 缓冲区,此时只在内核态进行操作,不会产生用户态和内核态切换,数据搬运过程由CPU完成。
  3. 最后,将内核的 socket 缓冲区数据拷贝到网卡中的数据缓冲区,这一步由DMA控制器操作。

我们可以得知,通过使用 mmap() 替代 read(),可以减少一次数据拷贝的过程。然而,这仍然不是最理想的零拷贝方式,因为仍然需要通过 CPU 将内核缓冲区的数据拷贝到 socket 缓冲区,且仍然需要进行 4 次上下文切换,因为系统调用仍然发生了两次。

接下来,我们来看第二种实现零拷贝的方式 - sendfile。

sendfile

在 Linux 内核版本 2.1 中,引入了一个名为sendfile()的系统调用函数,它提供了一种更高效的文件发送方法。sendfile()函数的使用方式如下:

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);	

该函数的前两个参数是目标端和源端的文件描述符,后面两个参数分别表示源端的偏移量和要复制的数据长度。函数的返回值是实际复制数据的长度。

sendfile()函数具有以下优点:

首先,它可以代替之前需要使用read()和write()两个系统调用的操作,从而减少了一次系统调用的开销。尽管sendfile()函数本身仍然需要进行系统调用,但仍然能够减少了2次上下文切换的开销。

其次,该系统调用可以直接将内核缓冲区中的数据复制到套接字缓冲区中,而无需再复制到用户态。这样一来,只需要进行2次上下文切换和3次数据拷贝。下图展示了这一过程的流程:

image

然而,这个过程仍然不能被称为真正的零拷贝技术。如果我们的网卡支持SG-DMA(散射-聚集直接内存访问)技术,与普通的DMA有所不同,那么我们可以进一步减少通过CPU将内核缓冲区中的数据拷贝到套接字缓冲区的过程。

你可以在你的Linux系统上使用以下命令来查看网卡是否支持散射-聚集特性::

$ ethtool -k eth0 | grep scatter-gather
scatter-gather: on

因此,从Linux内核2.4版本开始,在网卡支持SG-DMA技术的情况下,sendfile()系统调用的过程发生了一些变化,具体过程如下:

第一步,通过DMA将磁盘上的数据拷贝到内核缓冲区中;

第二步:内核缓冲区只需要将描述符和数据长度发送给套接字缓冲区,然后将直接通过SG-DMA将内核缓冲区中的数据拷贝到网卡的缓冲区中,这个过程不再需要从操作系统的内核缓冲区中拷贝到套接字缓冲区,从而减少了一次数据拷贝的过程。

因此,在这个过程中,只进行了两次数据拷贝,如下图所示:

image

这就是所谓的零拷贝(Zero-copy)技术,因为我们没有在内存层面进行数据拷贝,也就是说在整个过程中没有使用CPU来传输数据,而是完全依靠DMA来进行数据传输。

相比传统的文件传输方式,零拷贝技术可以减少2次上下文切换和数据拷贝的次数,只需要进行2次上下文切换和数据拷贝,就能完成文件的传输。而且这2次数据拷贝过程都不需要通过CPU,而是由DMA来进行数据传输。

因此,总体来看,零拷贝技术可以将文件传输的性能提升至少一倍以上。值得一提的是,在讲解零拷贝技术时,并没有提到网络协议是在哪个步骤中封装的。大家也应该知道,在内核中完成了网络协议的封装,而不是直接从缓冲区中取出数据并发送给网卡就结束了。

总结

本章主要介绍了零拷贝技术在文件传输中的优化方法。首先,通过减少用户态和内核态之间的上下文切换次数和数据拷贝次数来优化文件传输的性能。其次,介绍了两种实现零拷贝的方式:mmap + write和sendfile。通过使用mmap + write,可以将内核缓冲区的数据直接拷贝到socket缓冲区,减少一次数据拷贝过程。而使用sendfile系统调用,则可以进一步减少系统调用和数据拷贝次数。若网卡支持SG-DMA技术,还可以通过DMA将内核缓冲区的数据直接拷贝到网卡缓冲区,实现真正的零拷贝。

标签:DMA,传输,内核,缓冲区,拷贝,上下文,数据
From: https://blog.51cto.com/StudiousXiaoYu/7593297

相关文章

  • 零拷贝
    https://www.bilibili.com/video/BV1514y1h7Ve......
  • [转]Websocket 底层是 TCP 还是 UDP?白话版解析 TCP 和 UDP 传输过程
    原文地址:Websocket底层是TCP还是UDP?白话版解析TCP和UDP传输过程-掘金写在前面在前面陆陆续续写了好几篇数字孪生相关的文章,而其中所涉及的一个其他项目比较不常使用的技术,网络通讯协议Websocket,这个协议主要用于服务器定时向客户端推送数据,相比HTTP更加适合数字......
  • 数据包的奇妙旅程:揭秘网络传输的7个关键步骤
    发送数据包我们前面已经了解到为什么网络需要分层,每一层都有自己的职责。在发送数据包的过程中,这些层扮演着不同的角色。它们的主要任务是将数据包进行层层封装后发送,并在接收端逐层解封装。就像下面的示意图所展示的那样,在部署在Linux服务器B上的服务端Nginx和Tomcat通过Socket......
  • 传输过中如何保证 数据既能不被篡改,又能不被窃取
    公加私解,私加公解公钥加密私钥解密,只能保证数据不会篡改,但是可以被窃取私钥加密公钥解密,只能保证数据不会窃取,但是可能被整个替换签名和信封数据取摘要,然后私钥加密这种做法可以加快速度,保证数据不被篡改,这种方式叫做签名数据取摘要,然后公钥加密这种方式可以加快速度,保证数据......
  • Hugging News #0918: Hub 加入分类整理功能、科普文本生成中的流式传输
    每一周,我们的同事都会向社区的成员们发布一些关于HuggingFace相关的更新,包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等,我们将其称之为「HuggingNews」。本期HuggingNews有哪些有趣的消息,快来看看吧!......
  • 解密TCP连接断开:四次挥手的奥秘和数据传输的安全
    TCP连接断开在当今数字化时代,互联网已经成为了人们生活中不可或缺的一部分。而在互联网的基础之上,TCP协议扮演着关键的角色,它负责着数据在网络中的可靠传输。在TCP连接的建立过程中,我们已经了解了三次握手的过程和原理。然而,连接的建立只是TCP协议的一部分,同样重要的是连接的断......
  • DTS Data Transfer Service 数据传输服务是什么
    DTS(DataTransferService,数据传输服务)是一种用于在不同数据库之间迁移数据的服务。DTS可以帮助用户在不同数据库、不同数据存储之间传输数据,以满足业务需求和技术升级等场景。DTS通常支持多种源数据库和目标数据库之间的数据迁移,如MySQL、PostgreSQL、Oracle、SQLServer等。D......
  • Python中统计、拷贝等方法的使用
    一、统计方法的使用#coding=utf-8#统计出list中正数和负数的个数list=[1,2,3,-1,-2,-3]#count()函数--统计列表中某个元素出现的次数#print(list.count(2))#len()函数--统计列表长度即列表中的元素总个数#print(len(list))list1=[iforiinlistifi>0]print(l......
  • windows中实现本地scp命令向服务器远程免密传输文件
     先安装git,官网:https://git-scm.com/  001、打开git,生成本地密钥文件ssh-keygen##然后全部回车  002、查看密钥文件 ......
  • shell批量执行命令与文件传输脚本
    shell批量执行命令与文件传输脚本需求:对未进行主机信任操作的服务器进行批量操作实现:由于ssh只能在交互模式中输入服务器密码进行登录登操作,不便于进行大批量服务器进行巡检或日志采集。sshpass恰好又解决了这个问题,使用ssh-ppasswd可以实现命令行输入密码操作,便于进行规模......