当前位置: 首页 > news >正文

零拷贝技术深入分析

一、零拷贝

在前面的文章“深浅拷贝、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,但在内存操作上确实是非常用益。
当然,万事万物不是说是绝对的,有的时候,抽象一下,加一层,如果能达到更好的效果,又不影响实际的使用的情况下,岂不更妙?千头万绪又回到始终坚持的原则,应用场景决定应用技术,实践是检验真理的标准。

相关文章:

零拷贝技术深入分析

一、零拷贝 在前面的文章“深浅拷贝、COW及零拷贝”中对零拷贝进行过分析&#xff0c;但没有举例子&#xff0c;也没有深入进行展开分析。本文将结合实际的例程对零拷贝进行更深入的分析和说明。 在传统的IO操作中&#xff0c;以文件通过网络传输为例 &#xff0c;一般会经历以…...

Android 基础入门 基础简介

1. 观察App运行日志 2.Android 开发设计的编程语言 koltin Java c c 3.工程目录结构 4.Gradle 5.build.gradle 文件解析 plugins {id("com.android.application")//用了哪些插件 主配置文件版本控制 所以这里不用写版本 }android {namespace "com.tiger.myap…...

HUAWEI 华为交换机 配置基于VLAN的MAC地址学习限制接入用户数量 配置示例

组网需求 如 图 2-15 所示&#xff0c;用户网络 1 通过 LSW1 与 Switch 相连&#xff0c; Switch 的接口为 GE0/0/1 。用户网络2通过 LSW2 与 Switch 相连&#xff0c; Switch 的接口为 GE0/0/2 。 GE0/0/1 、 GE0/0/2 同属于 VLAN2。为控制接入用户数&#xff0c;对 VLAN2 进…...

编程笔记 Golang基础 042 文件处理

编程笔记 Golang基础 042 文件处理 一、文件处理二、Go语言文件处理创建文件和写入内容打开文件并按模式读写读取文件内容更高级的文件和IO操作改变文件权限目录操作 小结 一、文件处理 文件处理是指在计算机科学中&#xff0c;对存储在磁盘或其他持久性存储介质上的文件进行的…...

linuxlsof详解

lsof 是 List Open File 的缩写, 它主要用来获取被进程打开文件的信息&#xff0c;我们都知道&#xff0c;在Linux中&#xff0c;一切皆文件&#xff0c;lsof命令可以查看所有已经打开了的文件&#xff0c;比如: 普通文件&#xff0c;目录&#xff0c;特殊的块文件&#xff0c;…...

学习JAVA的第十二天(基础)

目录 算法 查找算法 基本查找&#xff08;顺序查找&#xff09; 二分查找&#xff08;折半查找&#xff09; 分块查找 排序算法 冒泡排序 选择排序 插入排序 快速排序 递归算法 算法 算法&#xff08;Algorithm&#xff09;是指解题方案的准确而完整的描述&#xff…...

Vector集合源码分析

Vector集合源码分析 文章目录 Vector集合源码分析一、字段分析二、方法分析三、总结 内容如有错误或者其他需要注意的知识点&#xff0c;欢迎指正或者探讨补充&#xff0c;共同进步。 一、字段分析 //用于存储该集合中的所有数据对象&#xff0c;所以是基于数组实现的 protec…...

Unity引擎中光源都有哪几种,都有什么作用

本文由 简悦 SimpRead 转码&#xff0c; 原文地址 mp.weixin.qq.com Unity 引擎为了实现游戏场景的明暗和光影效果&#xff0c;提供了四种类型的光源&#xff0c;分别是方向光&#xff08;Directional Lights&#xff09;、点光源&#xff08;Point Lights&#xff09;、聚光灯…...

C语言中结构体成员访问操作符的含义及其用法

1.直接访问操作符 用法&#xff1a;结构体名.成员名。 含义&#xff1a;直接访问结构体中的成员变量。 示例&#xff1a; #include<stdio.h> struct student {char name[20];int age; }; int main() {//定义了一个结构体数组arrstruct student arr[4] { {"cxk&q…...

Kubeadmin方式部署Calico网络模式的K8s集群

目录 1.环境准备 2.配置内核参数 3.配置ntp时间服务器 4.配置持久化日志目录 5.升级物理机内核 6.配置ipvs服务 7.安装docker 8.安装kubeadm、kubectl、kubelet 9.导入k8s组件基础镜像 10.k8s初始化配置 11.配置calico网络 12.完成部署 1.环境准备 ###方案中涉及的…...

sparse transformer 常见稀疏注意力

参考&#xff1a; https://zhuanlan.zhihu.com/p/259591644 主要就是降低transformer自注意力模块的复杂度 复杂度主要就是 Q K^T影响的&#xff0c;稀疏注意力就是在Q点乘K的转置这模块做文章 下列式一些sparse transformer稀疏注意力方法 a、transformer原始的 &#xff0…...

力扣 第 125 场双周赛 解题报告 | 珂学家 | 树形DP + 组合数学

前言 整体评价 T4感觉有简单的方法&#xff0c;无奈树形DP一条路上走到黑了&#xff0c;这场还是有难度的。 T1. 超过阈值的最少操作数 I 思路: 模拟 class Solution {public int minOperations(int[] nums, int k) {return (int)Arrays.stream(nums).filter(x -> x <…...

基于springboot+vue的人格障碍诊断系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…...

Go-知识struct

Go-知识struct 1. struct 的定义1.1 定义字段1.2 定义方法 2. struct的复用3. 方法受体4. 字段标签4.1 Tag是Struct的一部分4.2 Tag 的约定4.3 Tag 的获取 githupio地址&#xff1a;https://a18792721831.github.io/ 1. struct 的定义 Go 语言的struct与Java中的class类似&am…...

SpringMVC 学习(十一)之数据校验

目录 1 数据校验介绍 2 普通校验 3 分组校验 4 参考文档 1 数据校验介绍 在实际的项目中&#xff0c;一般会有两种校验数据的方式&#xff1a;客户端校验和服务端校验 客户端校验&#xff1a;这种校验一般是在前端页面使用 JS 代码进行校验&#xff0c;主要是验证输入数据…...

软考55-上午题-【数据库】-数据库设计步骤1

一、数据库设计的步骤 新奥尔良法&#xff0c;四个主要阶段&#xff1a; 1、用户需求分析&#xff1a;手机用户需求&#xff0c;确定系统边界&#xff1b; 2、概念设计&#xff08;概念结构设计&#xff09;&#xff1a;是抽象概念模型&#xff0c;较理想的是采用E-R方法。 …...

速盾:使用cdn后速度慢是怎么回事?

CDN&#xff08;内容分发网络&#xff09;是一种通过将网站的静态内容分布到全球各地的服务器&#xff0c;从而提供更快速度和更好用户体验的技术。然而&#xff0c;有时候用户会遇到使用CDN后速度变慢的问题&#xff0c;下面将探讨几种可能的原因。 服务器选择错误: CDN服务通…...

考研复试类比社团招新,无所谓“公平”,导师选谁都是他的权力

这篇文章是抖音和b站上上传的同名视频的原文稿件&#xff0c;感兴趣的csdn用户可以关注我的抖音和b站账号&#xff08;GeekPower极客力量&#xff09;。同时这篇文章也为视频观众提供方便&#xff0c;可以更加冷静地分析和思考。文章同时在知乎发表。 我考研一战的时候计算机考…...

阿里面试,有点焦虑。。

恭喜发现宝藏&#xff01;搜索公众号【TechGuide】回复公司名&#xff0c;解锁更多新鲜好文和互联网大厂的笔经面经&#xff0c;目前已更新至美团、字节… 作者TechGuide【全网同名】 聊聊春招 春招来了&#xff0c;有些24届校招生可能还在做最后的努力&#xff0c;有些25届的…...

24计算机考研调剂 | 石家庄铁道大学

01石家庄铁道大学 智慧交通研究室招少量调剂学术型硕士&#xff08;数一英一320分以上工科专业&#xff09; 考研调剂招生信息 学校:石家庄铁道大学 专业:工学->计算机科学与技术->计算机应用技术 工学->测绘科学与技术->地图制图学与地理信息工程 工学->交…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...