• 作者:老汪软件技巧
  • 发表时间:2024-08-28 17:02
  • 浏览量:

引言

本文简单论述零拷贝技术,为的后续文章中为啥Kafka比RocketMQ快,其中就有一个根本原因之一,kafka 使用了零拷贝技术,而RocketMQ没有。故此本文先简单打基础。

正文

零拷贝(Zero-Copy)是一种计算机操作,它减少了CPU的负载,因为数据不需要从一个内存区域复制到另一个内存区域。在传统的数据传输操作中,数据通常会在用户空间和内核空间之间进行多次复制,这不仅消耗CPU周期,还增加了系统的延迟。在文件传输的上下文中,零拷贝技术可以直接从文件系统缓存(页缓存)传输数据到网络接口,而无需将数据复制到用户空间缓冲区中。这通常是通过操作系统提供的特定系统调用来实现的,

如Linux中的sendfile系统调用。

下面是一个传统数据传输与零拷贝传输的对比:

传统数据传输流程(多次拷贝):从磁盘读取数据到内核空间的缓冲区。从内核空间复制数据到用户空间的缓冲区。从用户空间缓冲区复制数据回内核空间的socket缓冲区。从socket缓冲区将数据传输到网络。

在这个过程中,数据在用户空间和内核空间之间被复制了两次,增加了CPU的工作负担。

零拷贝数据传输流程(减少拷贝):从磁盘读取数据到内核空间的页缓存。直接从页缓存传输数据到网络接口。

在零拷贝流程中,数据不需要复制到用户空间,也不需要从用户空间复制回内核空间,从而减少了CPU的负担,降低了系统调用的开销,减少了上下文切换,提高了数据传输的效率。

零拷贝技术在高性能网络应用中非常重要,特别是在需要高速传输大量数据的场景,如文件服务器、数据库、消息队列系统(如Kafka)等。使用零拷贝可以显著提高这些应用的性能。

mmap 和 sendfile 是两种常用的零拷贝技术,它们各自有不同的用途和工作原理。下面详细解释这两种系统调用:

mmap

mmap(内存映射)系统调用允许应用程序将文件或设备的内容映射到进程的地址空间。这意味着文件可以被当作内存数组来访问,而无需使用传统的 read 和 write 系统调用。mmap 的工作原理如下:

应用程序调用 mmap,请求将文件映射到其虚拟地址空间。操作系统创建一段虚拟内存区域,并将这段内存与文件内容关联起来,但此时并不立即加载文件数据。当应用程序访问这段内存时,如果所需数据尚未加载,则会触发一个页面错误(page fault)。页面错误处理程序负责将磁盘上的数据加载到物理内存中,然后映射到进程的虚拟地址空间。一旦数据被加载,应用程序就可以像访问普通内存一样访问文件内容,而无需进行数据复制。

拷贝功能_拷贝原理_

mmap 的优点是可以通过内存访问文件,减少了将文件内容读取到用户空间缓冲区的需要。但是,mmap 并不总是完全没有数据复制,因为它依赖于页缓存,所以在某些情况下,如写操作,仍然需要将数据从页缓存复制到用户空间。

mmap 时序图:

sequenceDiagram
    participant User Space
    participant Kernel Space
    participant File System
    participant Memory Manager
    User Space->>Kernel Space: mmap() syscall
    Kernel Space->>Memory Manager: Create VMA for file
    Kernel Space->>User Space: Return pointer to mapped area
    User Space->>Memory Manager: Access mapped area (page fault)
    Memory Manager->>File System: Load data from file to page cache
    File System->>Memory Manager: Data loaded into page cache
    Memory Manager->>User Space: Map page to process's address space
    User Space->>User Space: Continue with execution

时序图解释:

用户空间(User Space)调用 mmap() 系统调用。内核空间(Kernel Space)请求内存管理器(Memory Manager)为文件创建一个虚拟内存区域(VMA,Virtual Memory Area)。内核空间将映射区域的指针返回给用户空间。用户空间访问映射区域,如果需要的数据页不在内存中,则会触发页面错误(page fault)。内存管理器向文件系统(File System)请求从文件加载数据到页缓存(page cache)。文件系统将数据加载到页缓存。内存管理器将数据页映射到进程的地址空间。用户空间继续执行,现在可以直接访问映射的文件数据。sendfile

sendfile 系统调用是专门设计用来在两个文件描述符之间高效地传输数据,常用于将数据从文件直接发送到网络套接字。sendfile 的工作原理如下:

应用程序调用 sendfile 并指定源文件描述符(通常是打开文件的描述符)和目标文件描述符(通常是网络套接字)。操作系统将源文件的数据读取到内核空间的页缓存中(如果数据还不在页缓存中)。然后操作系统直接将数据从页缓存传输到目标文件描述符的传输缓冲区,这通常是一个网络套接字的发送缓冲区。网络接口负责将数据从套接字缓冲区发送到网络上。

sendfile 的优点在于它完全避免了用户空间和内核空间之间的数据复制,因为数据在内核空间内部传输。这大大减少了CPU的使用和上下文切换,提高了文件传输的效率。

sendfile 时序图:

sequenceDiagram
    participant User Space
    participant Kernel Space
    participant File System
    participant Network Stack
    User Space->>Kernel Space: sendfile() syscall
    Kernel Space->>File System: Request file data
    File System->>Kernel Space: File data in page cache
    Kernel Space->>Network Stack: Copy data to socket buffer
    Network Stack->>Kernel Space: Transmit data over network
    Kernel Space->>User Space: Return the number of bytes sent

时序图解释:

用户空间(User Space)调用 sendfile() 系统调用。内核空间(Kernel Space)向文件系统(File System)请求文件数据。文件系统将文件数据放入内核的页缓存(page cache)。内核空间将数据从页缓存复制到网络栈(Network Stack)的套接字缓冲区(socket buffer)。网络栈负责将数据从套接字缓冲区通过网络传输。传输完成后,内核空间将发送的字节数返回给用户空间。

总结来说,mmap 允许文件以内存的形式被访问,适用于需要随机访问文件数据的情况。而 sendfile 是为了在文件和套接字之间快速传输数据而设计的,它在处理静态文件传输到网络客户端的场景(如Web服务器)中非常高效。两者都是零拷贝技术的实现,它们通过减少不必要的数据复制来提升性能。

结论

零拷贝技术是提升数据传输效率的有效手段之一。通过减少CPU参与的数据拷贝次数,它不仅提升了性能,还降低了系统的资源消耗。随着数据中心和云计算的发展,零拷贝技术将继续在优化系统性能方面发挥重要作用。