您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

零拷贝技术详解

时间:2023-06-21 15:18:50  来源:  作者:尚硅谷教育

当涉及到网络编程和IO操作时,数据拷贝是一个常见的性能瓶颈。传统的数据拷贝过程中,数据需要从内核缓冲区复制到用户空间缓冲区,然后再从用户空间缓冲区复制到内核缓冲区,这个过程会耗费大量的CPU时间和内存带宽,降低系统的性能和吞吐量。

为了解决这个问题,零拷贝技术应运而生。零拷贝技术是指在数据传输过程中,避免将数据从一块内存拷贝到另一块内存,从而减少了CPU的开销和内存带宽的消耗,提高了系统的性能。

JAVA后端开发中,使用零拷贝技术可以有效提升系统的性能和吞吐量。本文将介绍零拷贝技术的概念、实现原理以及在Java后端开发中的应用,希望能够为读者提供有价值的参考和帮助。

一、传统I/O

在展开说零拷贝之前,我们先来回顾一下传统IO的方式是怎么样的。

早期的数据IO,由用户进程向CPU发起,应用程序与磁盘之间的 I/O 操作都是通过 CPU 的中断完成的。CPU还要负责将磁盘缓冲区拷贝到内核缓冲区(pageCache),再从内核缓冲区拷贝到用户缓冲区。为了减少CPU占用,产生了DMA技术,大大解放了CPU。

DMA 的全称叫直接内存存取(Direct Memory Access),是一种允许外围设备(硬件子系统)直接访问系统主内存的机制。目前大多数的硬件设备,包括磁盘控制器、网卡、显卡以及声卡等都支持 DMA 技术。

1.1传统I/O的问题

我们以读取一张图片数据的过程为例来分析传统IO有哪些问题。传统的访问方式是通过 write() 和 read() 两个系统调用实现的,通过 read() 函数读取图片到到缓存区中,然后通过 write() 方法把缓存中的图片输出到网络端口。

read操作:

当应用程序执行 read 系统调用读取一块数据的时候,如果这块数据已经存在于用户进程的页内存中,就直接从内存中读取数据。

如果数据不存在,则先将数据从磁盘加载数据到内核空间的读缓存(read buffer)中,再从读缓存拷贝到用户进程的页内存中。

write操作:

当应用程序准备好数据,执行 write 系统调用发送网络数据时,先将数据从用户空间的页缓存拷贝到内核空间的网络缓冲区(socket buffer)中,然后再将写缓存中的数据拷贝到网卡设备完成数据发送。

从上图中可以看出,整个IO的过程需要进行两次DMA拷贝,两次CPU拷贝,四次上下文切换。总共四次拷贝,四次切换。这个代价确实有些大。

说完传统IO,接下来我们看下零拷贝都做了哪些优化。

二、零拷贝

2.1什么是零拷贝

零拷贝这个词,在很多地方都出现过,比如Kafka、NginxTomcat等等这些技术的底层都有用到零拷贝技术,那么究竟什么是零拷贝呢?

零拷贝是指在数据传输过程中,避免了数据的多次拷贝,从而提高了数据传输的效率。在传统的IO模型中,数据从磁盘中读取到内核缓冲区,然后再从内核缓冲区拷贝到用户缓冲区,最后再从用户缓冲区拷贝到应用程序中。而在零拷贝模型中,数据可以直接从内核缓冲区拷贝到应用程序中,避免了数据的多次拷贝,提高了数据传输的效率。零拷贝技术可以通过mmap和sendfile等系统调用实现。

所以说零拷贝并不是说不拷贝,而是减少拷贝的次数,因为从磁盘中拷贝数据到内存,或者从内存中的一块儿区域拷贝到另一块儿区域都是一个耗费性能的操作。零拷贝技术的目的就是减少这种行为的发生次数以此来提高性能。

2.2零拷贝实现的几种方式

对比开头说到的传统IO,我们可以在以下几个方面进行优化

1. 用户态可以直接操作读写,不需要在用户态和内核态之间反复横跳。

2. 尽量减少拷贝次数,尽量减少上下文切换次数。

3. 写时复制,需要写操作的时候再拷贝,只是读操作没必要拷贝

用户态直接IO

用户态直接 I/O 使得应用进程或运行在用户态(user space)下的库函数直接访问硬件设备。

用户态直接 I/O 只能适用于不需要内核缓冲区处理的应用程序,这些应用程序通常在进程地址空间有自己的数据缓存机制,称为自缓存应用程序,如数据库管理系统 就是一个代表。

其次,这种零拷贝机制会直接操作磁盘 I/O,由于 CPU 和磁盘 I/O 之间的执行时间差距,会造成大量资源的浪费,解决方案是配合异步 I/O 使用。

写时复制

写时复制指的是当多个进程共享同一块数据时,如果其中一个进程需要对这份数据进行修改,那么就需要将其拷贝到自己的进程地址空间中。

这样做并不影响其他进程对这块数据的操作,每个进程要修改的时候才会进行拷贝,所以叫写时拷贝。

减少拷贝次数

1. mmap+write零拷贝技术

以mmap+write的方式替代传统的read+write的方式,减少了一次拷贝。

mmap 是 linux 提供的一种内存映射文件方法,即将一个进程的地址空间中的一段虚拟地址映射到磁盘文件地址使用 mmap 的目的是将内核中读缓冲区(read buffer)的地址与用户空间的缓冲区(user buffer)进行映射。从而实现内核缓冲区与应用程序内存的共享,省去了将数据从内核读缓冲区(read buffer)拷贝到用户缓冲区(user buffer)的过程。

整个拷贝过程会发生 4 次上下文切换,1 次 CPU 拷贝和 2 次 DMA 拷贝。mmap 主要的用处是提高 I/O 性能,特别是针对大文件。对于小文件,内存映射文件反而会导致碎片空间的浪费。

2. Sendfile零拷贝技术

通过 Sendfile 系统调用,数据可以直接在内核空间内部进行 I/O 传输,从而省去了数据在用户空间和内核空间之间的来回拷贝。

将要读取的文件缓冲区的文件 fd 和要发送的Socket缓冲区的Socket fd 传给sendfile函数,Sendfile 调用中 I/O 数据对用户空间是完全不可见的。也就是说,这是一次完全意义上的数据传输过程。也就是说用户程序不能对数据进行修改,而只是单纯地完成了一次数据传输过程。整个拷贝过程会发生 2 次上下文切换,1 次 CPU 拷贝和 2 次 DMA 拷贝。

3. Sendfile+DMA gather copy

它只适用于将数据从文件拷贝到 socket 套接字上的传输过程。

它将内核空间的读缓冲区(read buffer)中对应的数据描述信息(内存地址、地址偏移量)记录到相应的网络缓冲区( socket buffer)中,由 DMA 根据内存地址、地址偏移量将数据批量地从读缓冲区(read buffer)拷贝到网卡设备中。

这样 DMA 引擎直接利用 gather 操作将页缓存中数据打包发送到网络中即可,本质就是和虚拟内存映射的思路类似。

整个拷贝过程会发生 2 次上下文切换、0 次 CPU 拷贝以及 2 次 DMA 拷贝。

4.Splice零拷贝技术

Splice相当于在Sendfile+DMA gather copy上的提升,Splice 系统调用可以在内核空间的读缓冲区(read buffer)和网络缓冲区(socket buffer)之间建立管道(pipeline),从而避免了两者之间的 CPU 拷贝操作。

基于 Splice 系统调用的零拷贝方式,整个拷贝过程会发生 2 次上下文切换,0 次 CPU 拷贝以及 2 次 DMA 拷贝。

2.3总结

无论是传统I/O拷贝方式,还是引入了零拷贝的方式,2次DMA Copy都是必要的步骤,因为两次DMA都是依赖硬件完成的。

三、零拷贝的实际应用

3.1JavaNIO基于零拷贝的实现

Java-NIO:主要有三个方面用到了零拷贝技术:

MAppedByteBuffer.map():底层调用了操作系统的mmap()内核函数。

DirectByteBuffer.allocateDirect():可以直接创建基于本地内存的缓冲区。

FileChannel.transferFrom()/transferTo():底层调用了sendfile()内核函数。

3.2主流技术中零拷贝的应用

1..NETty中零拷贝的应用

Netty中的零拷贝是一种用户进程级别的零拷贝体现,主要也包含三方面:

1) Netty的发送、接收数据的ByteBuf缓冲区,默认会使用堆外本地内存创建,采用直接内存进行Socket读写,数据传输时无需经过二次拷贝。如果使用传统的堆内存进行Socket网络数据读写,JVM需要先将堆内存中的数据拷贝一份到直接内存,然后才写入Socket缓冲区中,相较于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。

2)Netty的文件传输采用了transferTo()/transferFrom()方法,它可以直接将文件缓冲区的数据发送到目标Channel(Socket),底层就是调用了sendfile()内核函数,避免了文件数据的CPU拷贝过程。

3)Netty提供了组合、拆解ByteBuf对象的API,咱们可以基于一个ByteBuf对象,对数据进行拆解,也可以基于多个ByteBuf对象进行数据合并,这个过程中不会出现数据拷贝,这个是程序级别的零拷贝,实际上就是在原数据的基础上用不同的引用表示而已。

2. 其他技术中的零拷贝技术应用

Kafka底层基于java.nio包下的FileChannel.transferTo()实现零拷贝。Kafka Server基于FileChannel将文件中的消息数据发送到SocketChannel。

RocketMQ基于mmap + write的方式实现零拷贝。内部实现基于nio提供的java.nio.MappedByteBuffer,基于FileChannel的map方法得到mmap的缓冲区。



Tags:零拷贝   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
零拷贝并非万能解决方案:重新定义数据传输的效率极限
/ PageCache 有什么作用? /在我们前面讲解零拷贝的内容时,我们了解到一个重要的概念,即内核缓冲区。那么,你可能会好奇内核缓冲区到底是什么?这个专有名词就是 PageCache,也被称为...【详细内容】
2023-09-13  Search: 零拷贝  点击:(319)  评论:(0)  加入收藏
深入探究 Linux 中的零拷贝技术
零拷贝技术的发展在不同场景下有不同的适用方法。而在Linux操作系统中,现存的零拷贝技术也非常多,它们大部分存在于不同的Linux内核版本,而有些旧的技术已经被新技术所取代。本...【详细内容】
2023-09-04  Search: 零拷贝  点击:(239)  评论:(0)  加入收藏
搞明白什么是零拷贝,就是这么简单
我们总会在各种地方看到零拷贝,那零拷贝到底是个什么东西。接下来,让我们来理一理啊。拷贝说的是计算机里的 I/O 操作,也就是数据的读写操作。计算机可是一个复杂的家伙,包括软...【详细内容】
2023-08-26  Search: 零拷贝  点击:(266)  评论:(0)  加入收藏
零拷贝技术详解
当涉及到网络编程和IO操作时,数据拷贝是一个常见的性能瓶颈。传统的数据拷贝过程中,数据需要从内核缓冲区复制到用户空间缓冲区,然后再从用户空间缓冲区复制到内核缓冲区,这个过...【详细内容】
2023-06-21  Search: 零拷贝  点击:(358)  评论:(0)  加入收藏
一文读懂计算机内核态、用户态和零拷贝技术
存储介质的性能话不多说,先看一张图,下图左边是磁盘到内存的不同介质,右边形象地描述了每种介质的读写速率。一句话总结就是越靠近cpu,读写性能越快。了解了不同硬件介质的读写...【详细内容】
2022-12-02  Search: 零拷贝  点击:(363)  评论:(0)  加入收藏
虚拟内存 & I/O & 零拷贝
作者:mosun,腾讯 PCG 后台开发工程师一、虚拟内存 1.1 虚拟内存引入我们知道计算机由 CPU、存储器、输入/输出设备三大核心部分组成,如下:CPU 运行速度很快,在完全理想的状态下,存...【详细内容】
2022-10-13  Search: 零拷贝  点击:(306)  评论:(0)  加入收藏
如何深入理解零拷贝技术
零拷贝技术是一种思想,指的是计算机操作时,CPU不需要先将数据从某处内存复制从某处内存复制到另一个特定区域。可见,零拷贝的特点是 CPU 不全程负责内存中的数据写入其他组件,CP...【详细内容】
2022-09-14  Search: 零拷贝  点击:(381)  评论:(0)  加入收藏
零拷贝技术
知识补充:1、DMA是直接内存访问(Direct Memory Access) 技术,早期 DMA 只存在在主板上,如今由于 I/O 设备越来越多,数据传输的需求也不尽相同,所以每个 I/O 设备里面都有自己的 D...【详细内容】
2022-06-28  Search: 零拷贝  点击:(328)  评论:(0)  加入收藏
网络IO是如何一步一步走向零拷贝的
你们知道当程序需要读取或者写入数据的时候,CPU是如何操作我们的磁盘的吗?首先CPU肯定是要把读写数据的命令告诉给磁盘,这个命令可以通过IO总线传给磁盘,那这里有个细节,其实我们...【详细内容】
2022-04-12  Search: 零拷贝  点击:(274)  评论:(0)  加入收藏
一文让你彻底搞清楚,Linux零拷贝技术的那些事儿
1.前言像大白这种调包侠,深知不懂底层技术点就如同空中楼阁,再这样下去面阿里p10是没希望了。想到这里,我开始慌了,所以今天和大家一起学习个底层技术点-零拷贝Zero-Copy。Linux...【详细内容】
2022-02-25  Search: 零拷贝  点击:(353)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(6)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条