零拷贝技术、常见实现方案、Kafka中的零拷贝技术的使用、Kafka为什么这么快

目录

1. 普通拷贝

2. 数据拷贝基础过程

2.1 仅CPU方式

2.2 CPU&DMA方式

3.普通模式数据交互

4. 零拷贝技术

4.1 出现原因

4.2 解决思路

4.2.1 mmap方式

4.2.2 sendfile方式

4.2.3 sendfile+DMA收集

4.2.4 splice方式

5. Kafka中使用到的零拷贝技术

参考链接

本文参考这篇文章书写:【linux】图文并茂|彻底搞懂零拷贝(Zero-Copy)技术 - 知乎 (zhihu.com)


1. 普通拷贝

        考虑这样一种常用的情形:你需要将静态内容(类似图片、文件)展示给用户。这个情形就意味着需要先将静态内容从磁盘中复制出来放到一个内存 buf 中,然后将这个 buf 通过套接字(Socket)传输给用户,进而用户获得静态内容。可以将其抽象为如下伪代码:

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

        首先通过read() 将静态内容读取到用户缓冲区,然后调用write()将用户缓冲区的内容写入到Socket。

在这个过程中,普通文件(A)需要经过4次复制过程:

  1. 调用read(),将文件A的内容复制到内核模式的Read Buffer中。
  2. CPU控制将内核模式数据复制到用户模式下。
  3. 调用write(),将用户模式下的内容复制到内核模式下的Socket Buffer中。
  4. 将内核模式下的Socket Buffer的数据复制到网卡设备中传输。

        Linux系统中一切皆文件,仔细想一下Linux系统的很多活动无外乎读操作写操作,零拷贝就是为了提高读写性能而出现的。

2. 数据拷贝基础过程

        在Linux系统内部缓存和内存容量都是有限的,更多的数据都是存储在磁盘中。对于Web服务器来说,经常需要从磁盘中读取数据到内存,然后再通过网卡传输给用户:

上述数据流转只是大框,接下来看看几种模式。

2.1 仅CPU方式

  • 当应用程序需要读取磁盘数据时,调用read()从用户态陷入内核态,read()这个系统调用最终由CPU来完成;
  • CPU向磁盘发起I/O请求,磁盘收到之后开始准备数据;
  • 磁盘将数据放到磁盘缓冲区之后,向CPU发起I/O中断,报告CPU数据已经Ready了;
  • CPU收到磁盘控制器的I/O中断之后,开始拷贝数据,完成之后read()返回,再从内核态切换到用户态;

2.2 CPU&DMA方式

        CPU的时间宝贵,让它做杂活就是浪费资源。

        直接内存访问(Direct Memory Access),是一种硬件设备绕开CPU独立直接访问内存的机制。所以DMA在一定程度上解放了CPU,把之前CPU的杂活让硬件直接自己做了,提高了CPU效率。

        目前支持DMA的硬件包括:网卡、声卡、显卡、磁盘控制器等。

有了DMA的参与之后的流程发生了一些变化:

最主要的变化是,CPU不再和磁盘直接交互,而是DMA和磁盘交互并且将数据从磁盘缓冲区拷贝到内核缓冲区,之后的过程类似。

“【 敲黑板】无论从仅CPU方式和DMA&CPU方式,都存在多次冗余数据拷贝和内核态&用户态的切换。

我们继续思考Web服务器读取本地磁盘文件数据再通过网络传输给用户的详细过程。

3.普通模式数据交互

一次完成的数据交互包括几个部分:系统调用syscall、CPU、DMA、网卡、磁盘等。

系统调用syscall是应用程序和内核交互的桥梁,每次进行调用/返回就会产生两次切换:

  • 调用syscall 从用户态切换到内核态
  • syscall返回 从内核态切换到用户态

来看下完整的数据拷贝过程简图:

读数据过程:

  • 应用程序要读取磁盘数据,调用read()函数从而实现用户态切换内核态,这是第1次状态切换;
  • DMA控制器将数据从磁盘拷贝到内核缓冲区,这是第1次DMA拷贝;
  • CPU将数据从内核缓冲区复制到用户缓冲区,这是第1次CPU拷贝;
  • CPU完成拷贝之后,read()函数返回实现用户态切换用户态,这是第2次状态切换;

写数据过程:

  • 应用程序要向网卡写数据,调用write()函数实现用户态切换内核态,这是第1次切换;
  • CPU将用户缓冲区数据拷贝到内核缓冲区,这是第1次CPU拷贝;
  • DMA控制器将数据从内核缓冲区复制到socket缓冲区,这是第1次DMA拷贝;
  • 完成拷贝之后,write()函数返回实现内核态切换用户态,这是第2次切换;

综上所述:

  • 读过程涉及2次空间切换、1次DMA拷贝、1次CPU拷贝;
  • 写过程涉及2次空间切换、1次DMA拷贝、1次CPU拷贝;

可见传统模式下,涉及多次空间切换和数据冗余拷贝,效率并不高,接下来就该零拷贝技术出场了。

4. 零拷贝技术

4.1 出现原因

我们可以看到,如果应用程序不对数据做修改,从内核缓冲区到用户缓冲区,再从用户缓冲区到内核缓冲区。两次数据拷贝都需要CPU的参与,并且涉及用户态与内核态的多次切换,加重了CPU负担。

我们需要降低冗余数据拷贝、解放CPU,这也就是零拷贝Zero-Copy技术。

4.2 解决思路

目前来看,零拷贝技术的几个实现手段包括:mmap+write、sendfile、sendfile+DMA收集、splice等。

4.2.1 mmap方式

        mmap是Linux提供的一种内存映射文件的机制,它实现了将内核缓冲区地址与用户空间缓冲区地址进行映射,从而实现内核缓冲区与用户缓冲区的共享。这样就减少了一次用户态和内核态的CPU拷贝,但是在内核空间内仍然有一次CPU拷贝。

这样就减少了一次用户态和内核态的CPU拷贝,但是在内核空间内仍然有一次CPU拷贝。

mmap对大文件传输有一定优势,但是小文件可能出现碎片,并且在多个进程同时操作文件时可能产生引发coredump的signal。

4.2.2 sendfile方式

        sendfile是一种在网络传输中实现零拷贝的方式。sendfile() 是一种特殊的系统调用,它允许在内核空间和用户空间之间直接传输数据,避免了数据在内核和用户空间之间的额外拷贝。这在高性能的网络传输中非常有效。

        mmap+write方式有一定改进,但是由系统调用引起的状态切换并没有减少。

        sendfile系统调用是在 Linux 内核2.1版本中被引入,它建立了两个文件之间的传输通道。

        sendfile方式只使用一个函数就可以完成之前的read+write 和 mmap+write的功能,这样就少了2次状态切换,由于数据不经过用户缓冲区,因此该数据无法被修改。

从图中可以看到,应用程序只需要调用sendfile函数即可完成,只有2次状态切换、1次CPU拷贝、2次DMA拷贝。

但是sendfile在内核缓冲区和socket缓冲区仍然存在一次CPU拷贝,或许这个还可以优化。

4.2.3 sendfile+DMA收集

Linux 2.4 内核对 sendfile 系统调用进行优化,但是需要硬件DMA控制器的配合。

升级后的sendfile将内核空间缓冲区中对应的数据描述信息(文件描述符、地址偏移量等信息)记录到socket缓冲区中。

DMA控制器根据socket缓冲区中的地址和偏移量将数据从内核缓冲区拷贝到网卡中,从而省去了内核空间中仅剩1次CPU拷贝。

这种方式有2次状态切换、0次CPU拷贝、2次DMA拷贝,但是仍然无法对数据进行修改,并且需要硬件层面DMA的支持,并且sendfile只能将文件数据拷贝到socket描述符上,有一定的局限性。

4.2.4 splice方式

splice系统调用是Linux 在 2.6 版本引入的,其不需要硬件支持,并且不再限定于socket上,实现两个普通文件之间的数据零拷贝。

splice 系统调用可以在内核缓冲区和socket缓冲区之间建立管道来传输数据,避免了两者之间的 CPU 拷贝操作。

splice也有一些局限,它的两个文件描述符参数中有一个必须是管道设备。

5. Kafka中使用到的零拷贝技术

  • Producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入;
  • Customer从broker读取数据,采用sendfile,将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送。

参考链接

Kafka 中所谓的 ‘零拷贝’ 技术到底是什么?-腾讯云开发者社区-腾讯云 (tencent.com)

【linux】图文并茂|彻底搞懂零拷贝(Zero-Copy)技术 - 知乎 (zhihu.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/287510.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Intellij IDEA构建Android开发环境

Intellij IDEA创建项目时没有Android的选项 进设置(Intellij IDEA - Settings - Plugins ) 再次创建项目可以看到Android的选项 解决Android导入项目时Gradle下载速度慢/超时/失败

OpenHarmony内核编程实战

在正式开始之前,对于刚接触OpenHarmony的伙伴们,面对大篇幅的源码可能无从下手,不知道怎么去编码写程序,下面用一个简单的例子带伙伴们入门。 ▍任务 编写程序,让开发板在串口调试工具中输出”Hello,Open…

java Web会议信息管理系统 用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 jsp 会议信息管理系统是一套完善的web设计系统,对理解JSP java SERLVET mvc编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发,数据库为Mysql5.0&am…

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记11:数字电位器MCP4017

系列文章目录 嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记01:赛事介绍与硬件平台 嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记02:开发环境安装 嵌入式|蓝桥杯STM32G431(…

一周是一年的2%

今天读到阮一峰的293期周刊,其中有句话很让我震动——“一周是一年的2%”。 过去的时间里,我都没有在意时间的流逝,过的好的时候就觉得一周过的好快,周三一过这周也就过去了,过的不好的时候就感觉很漫长。 确实&…

C# wpf 嵌入hwnd窗口

WPF Hwnd窗口互操作系列 第一章 嵌入Hwnd窗口(本章) 第二章 嵌入WinForm控件 第三章 嵌入WPF控件 文章目录 WPF Hwnd窗口互操作系列前言一、如何实现1、继承HwndHost2、实现抽象方法3、xaml中使用HwndHost控件 二、具体实现1、Win32窗口2、HwndSource窗…

【Python】搭建 Python 环境

目 录 一.安装 Python二.安装 PyCharm 要想能够进行 Python 开发,就需要搭建好 Python 的环境 需要安装的环境主要是两个部分: 运行环境: Python开发环境: PyCharm 一.安装 Python (1) 找到官方网站 (2) 找到下载页面 选择 “Download for Windows”…

PHPCMS v9城市分站插件

PHPCMS自带的有多站点功能,但是用过的朋友都知道,自带的多站点功能有很多的不方便之处,例如站点栏目没法公用,每个站点都需要创建模型、每个站点都需要单独添加内容,还有站点必须静态化。如果你内容很多这些功能当然无…

Unity VisionOS开发流程

Unity开发环境 Unity Pro, Unity Enterprise and Unity Industry 国际版 Mac Unity Editor(Apple silicon) visionOS Build Support (experimental) 实验版 Unity 2022.3.11f1 NOTE: 国际版与国服版Pro账通用,需要激活Pro的许可证。官方模板v0.6.2,非Pro版本会打…

安科瑞智慧安全用电综合解决方案

概述 智慧用电管理云平台是智慧城市建设的延伸成果,将电力物联网技术与云平台的大数据分析功能相结合,实现用电信息的可视化管理,可帮助用户实现安全用电,节约用电,可靠用电。平台支持web,app,微…

【回眸】Tessy 单元测试软件使用指南(三)怎么打桩和指针赋值和测试

目录 前言 Tessy 如何进行打桩操作 普通桩 高级桩 手写桩 Tessy单元测试之指针相关测试注意事项 有类型的指针(非函数指针): 有类型的函数指针: void 类型的指针: 结语 前言 进行单元测试之后,但凡…

zookeeper面试题

文章目录 ZooKeeper 是什么?ZooKeeper 提供什么?1. 文件系统2. 通知机制 ZooKeeper 文件系统四种类型的 znode1. PERSISTENT (持久化目录节点)2. PERSISTENT_SEQUENTIAL (持久化顺序编号目录节点)3. EPHEMERAL (临时目录节点)4. EPHEMERAL_SEQUENTIAL (临…

C语言------指针(2)

前面已经向大家介绍了指针的一些基本内容,接下来,就在再我来先大家讲解一下指针的其他内容。 1. 数组名的理解 int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; 在学习数组的过程中,我们肯定会写过以上代码,我们知道 int 是该数组的数…

【C语言】C语言运算符优先级详解

文章目录 📝前言🌉运算符优先级简述 🌠逻辑与和逻辑或🌉赋值和逗号运算符 🌠位运算🌉条件表达式🌉位运算与算术运算结合🌉混合使用条件表达式和赋值运算符🌉 逗号运算符的…

UE5、CesiumForUnreal实现海量POI撒点显示与聚合功能

1.实现目标 POI是UE+GIS三维场景中经常需要展示的要素,在UE中常用的表示POI方法有两种。一种是Mesh,即空间的方式;另一种是Widget,即屏幕上的方式,本文这里使用的是Widget屏幕展示的形式来表示POI。 本文这里使用的POI点位数量共3.3w+,采用直接网格聚合算法,并进行性能优…

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件 0. 引言1. 安装 Markdown Viewer 插件2. 使用 Markdown Viewer 阅读 Markdown 格式文件 0. 引言 大部分程序员都喜欢 Markdown 格式的文件,这时给一些没有在电脑上安装 Markdown 编辑器的同事分享资料时&…

苹果与百度合作,将在iPhone 16中使用生成式AI

3月25日,《科创板日报》消息,苹果将与百度进行技术合作,为今年即将发布的iPhone16、Mac系统和iOS 18提供生成式AI(AIGC)功能。 据悉,苹果曾与阿里巴巴以及另外一家国产大模型厂商进行了技术合作洽谈。最终…

[自研开源] 数据集成之分批传输 v0.7

开源地址:gitee | github 详细介绍:MyData 基于 Web API 的数据集成平台 部署文档:用 Docker 部署 MyData 使用手册:MyData 使用手册 试用体验:https://demo.mydata.work 交流Q群:430089673 介绍 本篇基于…

Hana数据库 No columns were bound prior to calling SQLFetch or SQLFetchScroll

在php调用hana数据库的一个sql时报错了&#xff0c;查表结构的sql&#xff1a; select * from sys.table_columns where table_name VBAP SQLSTATE[SL009]: <<Unknown error>>: 0 [unixODBC][Driver Manager]No columns were bound prior to calling SQLFetch …

55、Qt/事件机制相关学习20240326

一、代码实现设置闹钟&#xff0c;到时间后语音提醒用户。示意图如下&#xff1a; 代码&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), speecher(new QTextToSpeech(t…