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

拷贝,技术,减少,数据,复制,上下文,切换,提高,网络,传输,效率 · 浏览次数 : 226

小编点评

**章 5:零拷贝技术优化方法** 本章将深入探讨零拷贝技术的优化方法,让我们一起走进零拷贝的优化之路! **优化文件传输的性能方法** 为了提高文件传输的性能,我们可以采取以下几个方法: - **减少用户态和内核态之间的上下文切换次数** - 使用 mmap() 替代 read() 系统调用函数,减少内核缓冲区数据复制的次数。 - 使用 sendfile() 系统调用函数,进一步减少内核缓冲区数据复制的次数。 - **减少数据拷贝的次数** - 使用 mmap() 替代 read() 系统调用函数,减少内核缓冲区数据复制的次数。 - 使用 sendfile() 系统调用函数,避免内存中数据复制的步骤。 - **优化内存分配** - 使用共享内存或其他技术,减少进程间通信带来的上下文切换。 - 在使用mmap() 或 sendfile() 系统调用时,根据实际需求调整内存分配的大小。 - **利用 SG-DMA 技术** - 如果网卡支持 SG-DMA 技术,可以通过 DMA 将内核缓冲区中的数据直接复制到网卡缓冲区中,实现真正的零拷贝。 **两种实现零拷贝的技术** **1. mmap() + write** - 使用 mmap() 替代 read() 系统调用函数,将内核缓冲区的数据直接复制到 socket 缓冲区。 - 使用 sendfile() 系统调用函数,将 socket 缓冲区的数据直接复制到网卡的缓冲区。 **2. sendfile()** - 使用 sendfile() 系统调用函数,直接将内核缓冲区中的数据复制到网卡的缓冲区。 **零拷贝技术的优点** - 减少 2 次上下文切换和数据拷贝的次数。 - 使用 DMA 将内核缓冲区中的数据直接复制到网卡缓冲区,避免内存中数据复制的步骤。 - 优化网络性能。 **总结** 本章介绍了零拷贝技术在文件传输中的优化方法,包括减少用户态和内核态之间的上下文切换次数和数据拷贝次数、减少数据拷贝的次数、优化内存分配和利用 SG-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技术在文件传输过程中的重要作用,并对零拷贝技术进行了简要介绍。然而,网络传输中存在的问题和优化方法是一个庞大的话题,涉及到诸多方面。因此,我决定将这些问题的详细讨论留到下一篇文章中,以便更全面地探讨网络传输的优化。我希望通过这样的讨论,能够为读者提供有益的信息和思路,感谢大家的阅读和关注,期待在下一篇文章中与大家再次交流和分享关于网络传输的优化问题。

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

本章节主要讨论了如何通过零拷贝技术来优化文件传输的性能。零拷贝技术主要通过减少用户态和内核态之间的上下文切换次数和数据拷贝次数来提高性能。具体来说,介绍了两种实现零拷贝的方式:mmap + write和sendfile。使用mmap + write可以减少一次数据拷贝过程,而使用sendfile系统调用可以进一步减少系统调用和数据拷贝次数。此外,还介绍了如果网卡支持SG-DMA技术,可以通过DMA将数据直接拷贝到网卡缓冲区,实现真正的零拷贝。通过这些优化方法,可以显著提高文件传输的性能。

零拷贝并非万能解决方案:重新定义数据传输的效率极限

本文讨论了零拷贝在优化数据传输效率方面的局限性。尽管零拷贝技术在减少数据传输过程中的内存拷贝次数方面有很大的优势,但它并非适用于所有情况。文章介绍了一些其他的优化方法,如异步I/O和直接I/O的组合、根据文件大小选择不同的优化方式。至此,我们的计算机基础专栏就结束了,不知道大家有没有发现,操作系统底层提供了丰富的解决方案来支持应用程序的复杂性和可扩展性。对于任何工作中遇到的问题,我们都可以从操作系统的角度寻找解决方法。

[转帖]sendfile“零拷贝”、mmap内存映射、DMA

https://www.jianshu.com/p/7863667d5fa7 KAFKA推送消息用到了sendfile,落盘技术用到了mmap,DMA贯穿其中。 先说说零拷贝 零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在IO读写过程中。 实际上,零拷贝是有广义和狭义之分,目前我们通常

科大讯飞:说说零拷贝技术和多路复用技术?

零拷贝技术和多路复用技术是现代计算机系统和网络编程中两项重要的优化手段,旨在提高数据处理和传输的效率。如高性能框架 Netty 中,即使用了零拷贝技术又使用了多路复用技术,同时来保证 Netty 框架的高性能运行。 1.零拷贝技术 零拷贝(Zero-copy)技术是一种计算机操作系统中用于提高数据传

美团面试:说说Netty的零拷贝技术?

零拷贝技术(Zero-Copy)是一个大家耳熟能详的技术名词了,它主要用于提升 IO(Input & Output)的传输性能。 那么问题来了,为什么零拷贝技术能提升 IO 性能? 1.零拷贝技术和性能 在传统的 IO 操作中,当我们需要读取并传输数据时,我们需要在用户态(用户空间)和内核态(内核空

[转帖]Linux中的零拷贝技术

https://www.jianshu.com/p/a757a93b6e5f 内存映射--mmap 内核和用户空间,共享内存。数据copy到内核区后,只需要把地址共享给应用程序即可,无需再copy一次数据到用户空间。 image.png 优点: 用户程序可以读取和修改共享内存的数据,就像读取用户空间

[转帖]从Linux零拷贝深入了解Linux-I/O

https://aijishu.com/a/1060000000375591 作者:kevineluo,腾讯 CSIG 后台开发工程师 本文将从文件传输场景以及零拷贝技术深究 Linux I/O 的发展过程、优化手段以及实际应用。 前言 存储器是计算机的核心部件之一,在完全理想的状态下,存储器应该要

从Linux零拷贝深入了解I/O

转载&学习文章:从Linux零拷贝深入了解I/O 本文将从文件传输场景以及零拷贝技术深究 Linux I/O 的发展过程、优化手段以及实际应用。 前言 存储器是计算机的核心部件之一,在完全理想的状态下,存储器应该要同时具备以下三种特性: 速度足够快:存储器的存取速度应当快于 CPU 执行一条指令,这

Kafka为什么这么快?

Kafka 是一个基于发布-订阅模式的消息系统,它可以在多个生产者和消费者之间传递大量的数据。Kafka 的一个显著特点是它的高吞吐率,即每秒可以处理百万级别的消息。那么 Kafka 是如何实现这样高得性能呢?本文将从七个方面来分析 Kafka 的速度优势。 - 零拷贝技术 - 仅可追加日志结构 -