零拷贝技术深入分析

一、零拷贝

在前面的文章“深浅拷贝、COW及零拷贝”中对零拷贝进行过分析,但没有举例子,也没有深入进行展开分析。本文将结合实际的例程对零拷贝进行更深入的分析和说明。
在传统的IO操作中,以文件通过网络传输为例 ,一般会经历以下几个数据拷贝的过程:
磁盘缓冲区 ->内核缓冲区->用户缓冲区->内核网络缓冲区->网卡缓冲区
也就是数据要经历从IO到内核空间,再从内核到用户空间再进入内核空间然后才能通过IO发走,至少要有四次的内在拷贝。
而这就引出了零拷贝的概念:尽最大可能减少CPU参与数据拷贝的过程(直到完全不参与拷贝)。它主要有基于内核缓冲优化的零拷贝和DirectIO的零拷贝。
仍然以上面的链路来分析,可不可以直接从硬盘把数据(内核缓冲区)拷贝到网卡缓冲区,可不可以?可不可以不过用户缓冲区直接在内核内交互数据?这都是直接想到的解决问题的方法和手段。而实际上,零拷贝技术也就是按这种指导思想进行开展的。
零拷贝技术的实现有以下几种方法:
1、DirectIO
这个好理解,不通过各种中间环节直接和IO打交道。它主要应用于上层应用本身实现了磁盘的数据缓存,比如常见的数据库系统软件,那么就不需要再使用PageCache进行缓冲。这样就可以减少PageCache(内核缓冲区)的消耗(这可略过了计算中最大的中间商CPU)。而诸如下面的sendfile等,其实都基于PageCache优化的零拷贝。
2、新的函数sendfile(win:TransmitFile)
sendfile是Linux系统提供的系统API,它可以解决用户空间和内核空间的数据拷贝的次数问题;如果其和DMA技术(重点指SG-DMA(The Scatter-Gather Direct Memory Access))共同工作即sendfile+DMA,那么其效率更高,可以直接把数据文件从磁盘拷贝到网络缓冲区 。
sendfile有其一定的局限性,首先是标准不统一,另外一个就是无法在数据操作中间在用户空间对数据进行操作,比如从磁盘加载然后加解密等然后再发送,因为得不到具体的数据 ,这需要引起重视。
3、函数splice
splice技术更进一步,它接近于 sendfile和DMA的进一步效率提高,此函数在内核空间和网络缓冲区间建立管道,避免二者的CPU的拷贝。注意,此函数中的两个文件操作符必须有一个为管道操作符。
4、mmap
mmap方式大家比较熟悉,这里就简单说明一下,其实mmap的零拷贝就是通过内存映射提供一个内核和用户空间直接通信的手段。mmap应用非常多,最典型的是安卓的应用,Framework层的数据通信很多是用mmap为实现的。
5、tee
tee函数用来在两个管道文件描述符间复制数据。它要求两个文件描述符都必须为管道描述符;同时,它在复制过程中保持原数据不动直接复制fd,而splice是移动数据从源fd到目的fd。注意二者的区别和不同。
下面就分别对几类技术实现方式进行举例分析。在分析之前,先对原来的文章“深浅拷贝、COW及零拷贝”中零拷贝的图进行一下完善:

在这里插入图片描述

主要是补齐了未描述清楚的普通DMA部分的流程。

二、sendfile

先看一下定义:

int main(int argc, char* argv[])
{
......int ffd = open(fname, O_RDONLY);//打开文件struct stat st;fstat(ffd, &st);struct sockaddr_in addr;bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;inet_pton(AF_INET, ip, &addr.sin_addr);addr.sin_port = htons(static_cast<uint16_t>(port));int s = socket(PF_INET, SOCK_STREAM, 0);int reuse = 1;//设置端口重用setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));int ret = bind(s, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));ret = listen(s, 3);struct sockaddr_in client;socklen_t client_addrlen = sizeof(client);int cSocket = accept(s, reinterpret_cast<struct sockaddr*>(&client), &client_addrlen);if (cSocket < 0) {printf("accept err: %d\n", errno);}else {sendfile(cSocket, ffd, NULL, static_cast<size_t>(st.st_size));close(cSocket);}......return 0;
}

注意上面的代码省略了相关的安全控制和参数赋值,大家可以自行设置,直接写成固定的就可以,只是一个测试程序么。

三、splice

splice的应用也不复杂,但需要注意其中的一些要求,特别是参数中,在Linux2.6.21以前,splice的flags设置SPLICE_F_MOVE有效,其后就无效了,但SPLICE_F_NONBLOCK 和SPLICE_F_MORE都有效果。看一下例程:

#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <libgen.h>
#include <assert.h>
#include <stdlib.h>int main(int argc, char* argv[])
{
......struct sockaddr_in addr;bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;inet_pton(AF_INET, ip, &addr.sin_addr);addr.sin_port = htons(static_cast<uint16_t>(port));int sfd = socket(PF_INET, SOCK_STREAM, 0);int reuse = 1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));int r = bind(sockfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));r = listen(sockfd, 3);struct sockaddr_in cSocket;socklen_t client_addrlen = sizeof(cSocket);int cfd = accept(sfd, reinterpret_cast<sockaddr*>(&cSocket), &client_addrlen);if (cfd < 0) {printf("accept err: %d\n", errno);}else {int pfd[2];ret = pipe(pfd);while (1) {ssize_t res;res = splice(cfd, NULL, pfd[1], NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);if (res == 0) { // 收到EOFbreak;}res = splice(pfd[0], NULL, cfd, NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);}close(cfd);}close(sfd);return 0;
}

相关的具体参数可以看说明文档,还是相当清楚的。

四、tee和mmap

mmap的例子非常多,这里只给一个tee相关的例子:


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libgen.h>
#include <assert.h>int main(int argc, char* argv[])
{
......int ffd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666);int pfdout[2];int r = pipe(pfdout);assert(r != -1);int pfdfile[2];r = pipe(pfdfile);while (1) {ssize_t res = splice(STDIN_FILENO, NULL, pfdout[1], NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);if (res == 0) {break;}res = tee(pfdout[0], pfdfile[1], 1024, SPLICE_F_NONBLOCK);res = splice(pfdfile[0], NULL, ffd, NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);assert(res != -1);// 二次调用,因为第一次调用数据已经移动,所以splice函数阻塞//res = splice(pfdfile[0], NULL, STDOUT_FILENO, NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);}.......return 0;
}

这些都没有什么难度,手册上也都有相关的例程。

五、DMA技术和零拷贝

在上面的分析过程中可以清晰的知道,DMA技术和零拷贝既有千丝万缕的联系,又有所不同:
DMA技术是负责数据的直通,零拷贝重点是CPU不参与数据拷贝,但需要参与数据的管理(比如数据可以使用,开始操作等等),也就是说DMA技术和零拷贝技术中的CPU互相协作,达到数据拷贝的次数最少的目的。
零拷贝其实就是考虑减少从IO到用户层的整个数据流程的拷贝次数从而提高效率,要始终抓住这条主线。DMA主要是拷贝,CPU重点是管理,即把CPU从既管理又复制中简化工作任务,只管理即可。DMA技术和硬件关系很密切,所以在具体的开发使用中,要明确硬件是否支持相关具体的操作。
需要注意的另外一点是,在实际场景中,如果是非常大的数据文件处理,基于PageCache零拷贝技术则有些力不从心了,还是得使用Direct IO的零拷贝技术。

六、使用零拷贝的框架

说一些技术和概念可能理解并不深刻,可以参考一下相关的一些开源框架中使用的零拷贝技术:
1、KAFKA
使用sendfile的零拷贝技术
2、Nginx
提供了sendfile和directio的相关零拷贝技术
3、Mysql
使用了directio的零拷贝技术
4、Netty
使用sendfile的零拷贝技术
5、RocketMQ
使用了mmap write的零拷贝技术

七、总结

其实说得更浅显一些,所谓零拷贝更准确的说不是零次拷贝,是指尽可能的减少拷贝。在DPDK的系列文章中,这种操作被发挥的淋漓尽致。互联网的口号就是“不让中间商赚差价”,这个在现实上可能有一些逻辑上的BUG,但在内存操作上确实是非常用益。
当然,万事万物不是说是绝对的,有的时候,抽象一下,加一层,如果能达到更好的效果,又不影响实际的使用的情况下,岂不更妙?千头万绪又回到始终坚持的原则,应用场景决定应用技术,实践是检验真理的标准。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

神经网络系列---卷积

文章目录 卷积神经网络卷积转置卷积 卷积核和反卷积的三种实现方式卷积的次数计算 卷积神经网络 在神经网络的卷积层中&#xff0c;向下取整&#xff08;Floor&#xff09;是一种常用的策略&#xff0c;特别是在处理输出尺寸不是整数的情况时。当你计算出卷积层输出的尺寸&…

Tomcat概念、安装及相关文件介绍

目录 一、web技术 1、C/S架构与B/S架构 1.1 http协议与C/S架构 1.2 http协议与B/S架构 2、前端三大核心技术 2.1 HTML&#xff08;Hypertext Markup Language&#xff09; 2.2 css&#xff08;Cascading Style Sheets&#xff09; 2.3 JavaScript 3、同步和异步 4、…

KakaoTalk数据库和加密文件密钥生成方法

KakaoTalk数据库密钥 KakaoTalk的数据库为sqlite3数据库&#xff0c;经过加密处理&#xff0c;不同类别的数据库采用不同的密钥加密。聊天记录的数据库由一个称为PRAGMA KEY的密钥进行加密&#xff0c;这里简称为PK。 PK的生成 PK的格式如下: ODSnnkkwyAHsXwgCEIQLCpAxdSZh…

【数学建模获奖经验】2023第八届数维杯数学建模:华中科技大学本科组创新奖获奖分享

2024年第九届数维杯大学生数学建模挑战赛将于&#xff1a;2024年5月10日08:00-5月13日09:00举行&#xff0c;近期同学们都开始陆续进入了备赛阶段&#xff0c;今天我们就一起来看看上一届优秀的创新奖选手都有什么获奖感言吧~希望能帮到更多热爱数学建模的同学。据说点赞的大佬…

20240301-2-ZooKeeper面试题(二)

11. Chroot 特性 3.2.0 版本后&#xff0c;添加了 Chroot 特性&#xff0c;该特性允许每个客户端为自己设置一个命名空间。如果一个客户端设置了 Chroot&#xff0c;那么该客户端对服务器的任何操作&#xff0c;都将会被限制在其自己的命名空间下。 通过设置 Chroot&#xff…

羊大师分享,羊奶奶有哪些对健康有益的喝法?

羊大师分享&#xff0c;羊奶奶有哪些对健康有益的喝法&#xff1f; 羊奶奶有多种对健康有益的喝法&#xff0c;以下是一些建议&#xff1a; 直接饮用&#xff1a;将羊奶直接煮沸后饮用&#xff0c;可以保留羊奶中的营养成分&#xff0c;为身体提供全面的滋养。羊奶的丰富蛋白质…

Spring11、整合Mybatis

11、整合Mybatis 步骤&#xff1a; 导入相关jar包 junit <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency> mybatis <dependency><groupId>org.my…

【MySQL】redo log和undo log

引入 在介绍redo log和undo log之前&#xff0c;我们需要了解 MySQL 中的两个概念&#xff1a;缓冲池和数据页。 缓冲池(buffer pool)&#xff1a;主内存中的一个区域&#xff0c;里面可以缓存磁盘上经常操作的真实数据&#xff0c;在执行 CRUD 操作时&#xff0c;先操作缓冲…

Java 封装阿里云 oss 上传图片时抽取配置到 application 使用 @Value 获取值

Java 封装阿里云 oss 上传图片时抽取配置到 application 使用 Value 获取值 application .yml 配置 alioss: # 阿里云配置endpoint: "https://oss-cn-beijing.aliyuncs.com" # Endpoint以华东1&#xff08;杭州&#xff09;为例&#xff0c;其它Region请按实际…

任务系统之API子任务

日常运维工作中有许多的任务要执行&#xff0c;例如项目发布/数据备份/定时巡检/证书更新/漏洞修复等等&#xff0c;大部分的任务都会有多个步骤共同完成&#xff0c;例如一个发布任务会有拉代码、编译、分发、通知等等步骤&#xff0c;而不同的任务可能还包含相同或相似的步骤…

应用稳定性优化1:ANR问题全面解析

闪退、崩溃、无响应、重启等是应用稳定性常见的问题现象&#xff0c;稳定性故障大体可归类为ANR/冻屏、Crash/Tombstone、资源泄露三大类。本文通过对三类故障的产生原因、故障现象、触发机制及如何定位等&#xff0c;展开深度解读。 本文将详解ANR类故障&#xff0c;并通过一…

如何在群晖Docker运行本地聊天机器人并结合内网穿透发布到公网访问

文章目录 1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 随着ChatGPT 和open Sora 的热度剧增,大语言模型时代,开启了AI新篇章,大语言模型的应用非常广泛&#xff0c;包括聊天机…

【MicroPython教程】SSD1306 oled

文章目录 前言一、OLED的介绍二、下载ssd1306驱动三、ssd1306驱动的使用3.1 oled屏连线3.2 初始化oled3.3 画图函数填充整个屏幕显示画点滚动写字画圆形画弧画无填充的矩形画填充矩形画线画xbm图像 四、示例代码——正弦函数总结 前言 SSD1306 OLED 是一种常见的小型显示屏&am…

​MPV,汽车产品里一个特殊品类的进化过程

「汽车」可能是整个工业革命以来&#xff0c;所诞生出的最有趣的工业产品。 它不仅能产生工业的机械美&#xff0c;还诞生了一个独立的文化体系&#xff0c;在汽车的发展过程中&#xff0c;我们也能看到一些本来应功能而诞生的产品&#xff0c;最终走向了千家万户。 MPV 就是…

【王道数据结构】【chapter8排序】【P371t6】

试设计一个算法&#xff0c;判断一个数据序列是否构成一个小根堆&#xff08;下面代码中的堆排序的部分仅仅是为了方便设计测试用例&#xff09; #include <iostream> #include<time.h> #include<stdlib.h>int * buildarray(int size) {int* tmp(int *) mall…

Java毕业设计-基于springboot开发的家政服务管理平台系统-毕业论文+答辩PPT(有源代码)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1.开发说明2.需求分析3、系统功能结构 三、系统实现展示1、前台模块设计2、后台功能模块2.1管理员功能模块2.2用户功能模块2.3服务人员功能模块 四、毕设内容和源代码获取总结 Java毕业设计…

P2040 打开所有的灯

题目传送门&#xff1a;P2040 打开所有的灯 用深度优先搜索实现的一个填色题。 题目步骤&#xff1a; 1..dfs 首先dfs要判断是否符合题意&#xff0c;如果符合题意就更新最短路&#xff1b; 如果不符合题意就枚举 如果是关的就把周围四个包括 给标记上和原来相反的&#xf…

文件怎么减小内存?4个简单的方法~

随着我们在电脑或移动设备上创建、下载和收集越来越多的文件&#xff0c;存储空间的管理变得尤为重要。有时&#xff0c;文件太大会占用过多的内存&#xff0c;导致存储空间不足的问题。但别担心&#xff0c;本文将向您介绍五种简单有效的方法&#xff0c;帮助您轻松减小文件的…

SpringBoot启动扩展应用:干预优化+加快启动时间(干货典藏版)

一、SpringBoot启动过程干预 Spring Boot启动过程中我们可以实现以下干预工作&#xff1a; 修改Spring Boot默认的配置属性。使用ConfigurationProperties和EnableConfigurationProperties注解&#xff0c;可以获取和修改Spring Boot的配置属性。 加载配置文件。Spring Boot会…

深度伪造,让网络钓鱼更加难以辨别

网络钓鱼一直是安全领域的一个突出话题&#xff0c;尽管这类诈骗形式已经存在了几十年&#xff0c;依旧是欺诈攻击或渗透组织的最有效方法之一。诈骗分子基于社会工程原理&#xff0c;通过邮件、网站以及电话、短信和社交媒体&#xff0c;利用人性&#xff08;如冲动、不满、好…