自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

三分鐘掌握零拷貝的那些事

開(kāi)發(fā) 前端
splice是在內(nèi)核空間的緩存區(qū)和socket緩存區(qū)之間建立管道,從而避免了兩者之間的CPU拷貝操作。?splice的整個(gè)拷貝過(guò)程發(fā)生了2次用戶態(tài)和內(nèi)核態(tài)的切換,2次數(shù)據(jù)的拷貝(2次DMA拷貝、0次CPU拷貝)。

零拷貝可以直觀的理解為不需要將數(shù)據(jù)從一個(gè)存儲(chǔ)區(qū)域拷貝到另外一個(gè)存儲(chǔ)區(qū)域,從而提高數(shù)據(jù)的效率。這里的零是指CPU參與整個(gè)拷貝過(guò)程的次數(shù)。下面我們來(lái)聊聊傳統(tǒng)的數(shù)據(jù)傳輸(write+read)和零拷貝的幾種實(shí)現(xiàn)方式的數(shù)據(jù)傳輸原理。

1、write+read數(shù)據(jù)傳輸?shù)脑?/span>

在我們的Java代碼中傳輸?shù)臄?shù)據(jù)時(shí)候會(huì)用到write方法,write方法寫(xiě)數(shù)據(jù)發(fā)送到網(wǎng)卡的過(guò)程如下圖所示:

圖片圖片

然后接收方使用read方法從網(wǎng)卡接收數(shù)據(jù)的流程如下圖所示:

圖片圖片

通過(guò)write+read的方式我們就可以實(shí)現(xiàn)數(shù)據(jù)的傳輸,但是在這兩個(gè)方法背后是需要做很多的工作,如下所示的原理圖:

圖片圖片

當(dāng)我們調(diào)用read方法的時(shí)候,首先需要從用戶態(tài)切換到內(nèi)核態(tài),然后通過(guò)DMA拷貝(Direct Memory Access,即直接內(nèi)存訪問(wèn)。DMA本質(zhì)上是一塊主板上獨(dú)立的芯片,允許外設(shè)設(shè)備和內(nèi)存存儲(chǔ)器之間直接進(jìn)行IO數(shù)據(jù)傳輸,其過(guò)程不需要CPU的參與)將磁盤(pán)里面的文件拷貝到內(nèi)核緩沖區(qū)上,數(shù)據(jù)拷貝到內(nèi)存緩沖區(qū)之后又需要進(jìn)行內(nèi)核態(tài)轉(zhuǎn)化為用戶態(tài),將內(nèi)核緩沖區(qū)中的數(shù)據(jù)拷貝到用戶緩沖區(qū)。這里涉及到2次的狀態(tài)切換、1次DMA拷貝、1次CPU拷貝。

文件數(shù)據(jù)拷貝到用戶緩存區(qū)之后,首先需要從用戶態(tài)切換到內(nèi)核態(tài),然后通過(guò)調(diào)用write方法,此時(shí)CPU就會(huì)將用戶緩存區(qū)的文件數(shù)據(jù)拷貝到內(nèi)核的socket緩存區(qū)上,最后通過(guò)DMA拷貝將數(shù)據(jù)拷貝到網(wǎng)卡上,當(dāng)數(shù)據(jù)拷貝到網(wǎng)卡成功后再?gòu)膬?nèi)核態(tài)切換到用戶態(tài)。

傳統(tǒng)的文件傳輸?shù)恼麄€(gè)過(guò)程中,涉及到了4次用戶態(tài)與內(nèi)核態(tài)的上下文切換,執(zhí)行了4次數(shù)據(jù)的拷貝(2次DMA拷貝、2次CPU拷貝)。

在文件數(shù)據(jù)傳輸?shù)倪^(guò)程中,我們的目的就是將磁盤(pán)的文件發(fā)送到網(wǎng)卡上

圖片圖片

但是文件數(shù)據(jù)需要經(jīng)過(guò)多個(gè)過(guò)程才能到達(dá)網(wǎng)卡,于是就研究人員提出了通過(guò)減少用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換或者減少內(nèi)存拷貝的次數(shù)的方式來(lái)提高文件拷貝的效率,這就是零拷貝技術(shù)產(chǎn)生的背景。

2、mmap + write

使用mmap+write方式替換原來(lái)的傳統(tǒng)IO方式,實(shí)質(zhì)就是利用了虛擬內(nèi)存。虛擬內(nèi)存在現(xiàn)代操作系統(tǒng)使用很廣泛,其特性如下所示:

(a)多個(gè)虛擬內(nèi)存可以指向同一個(gè)物理地址。

(b)虛擬內(nèi)存空間可以遠(yuǎn)遠(yuǎn)大于物理內(nèi)存空間。

mmap正是利用第一條特性,將內(nèi)核空間和用戶空間的虛擬地址映射到同一個(gè)物理地址,這樣在IO操作時(shí)就不需要來(lái)回復(fù)制了,如下所示的虛擬內(nèi)存示意圖:

圖片圖片

mmap + write實(shí)現(xiàn)的零拷貝的流程圖如下所示:

圖片圖片

當(dāng)調(diào)用mmap方法的時(shí)候,首先從用戶態(tài)切換到內(nèi)核態(tài),然后將磁盤(pán)文件使用DMA拷貝到內(nèi)核緩存區(qū),由于內(nèi)核緩沖區(qū)與用戶緩沖區(qū)已經(jīng)完成了映射(虛擬內(nèi)存),所以這個(gè)時(shí)候就不需要將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶緩存區(qū),當(dāng)數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)之后,又要從內(nèi)核態(tài)切換到用戶態(tài)。

當(dāng)調(diào)用write方法的時(shí)候,進(jìn)程要從用戶態(tài)切換到內(nèi)核態(tài),然后進(jìn)程直接操作內(nèi)核緩沖區(qū)里面的數(shù)據(jù)拷貝到socket緩沖區(qū)中,拷貝到socket緩沖區(qū)完成后,再通過(guò)DMA拷貝到網(wǎng)卡,網(wǎng)上數(shù)據(jù)拷貝完成之后又要從內(nèi)核態(tài)切換到用戶態(tài)。

整個(gè)過(guò)程還是存在了4次用戶態(tài)和內(nèi)核態(tài)的切換,發(fā)生了3次數(shù)據(jù)的拷貝(2次DMA拷貝、1次CPU拷貝),雖然相比于傳統(tǒng)的文件傳輸過(guò)程少了一次CPU拷貝,數(shù)據(jù)的傳輸?shù)男视幸欢ǖ奶嵘?/span>

3、sendfile

sendfile是Linux2.1版本提供的一個(gè)系統(tǒng)調(diào)用函數(shù),主要是負(fù)責(zé)發(fā)送文件的。只需要調(diào)用sendfile函數(shù)就可以完成整個(gè)文件拷貝的過(guò)程,如下圖所示的流程圖:

圖片圖片

當(dāng)調(diào)用sendfile的時(shí)候,首先需要從用戶態(tài)切換到內(nèi)核態(tài),使用DMA拷貝將文件拷貝到內(nèi)核緩存區(qū),然后將內(nèi)核緩存區(qū)的數(shù)據(jù)通過(guò)CPU拷貝到socket的緩存區(qū),最后再通過(guò)DMA拷貝數(shù)據(jù)到網(wǎng)卡上,完成網(wǎng)卡數(shù)據(jù)拷貝后再?gòu)膬?nèi)核態(tài)切換到用戶態(tài)。

sendfile實(shí)現(xiàn)數(shù)據(jù)傳輸?shù)?/span>過(guò)程存在了2次用戶態(tài)和內(nèi)核態(tài)的切換,發(fā)生了3次數(shù)據(jù)的拷貝(2次DMA拷貝、1次CPU拷貝),相比于mmap + write的方式又提升了一些效率。

4、sendfile + SG-DMA

在Linux2.4版本中網(wǎng)卡支持SG-DMA技術(shù),那么使用SG-DMA可以進(jìn)一步的優(yōu)化零拷貝的過(guò)程,如下所示的流程圖:

圖片圖片

當(dāng)調(diào)用sendfile的時(shí)候,首先用戶態(tài)切換到內(nèi)核態(tài),然后使用DMA拷貝將文件從磁盤(pán)拷貝到內(nèi)核緩存區(qū),接下來(lái)它就會(huì)將描述符和數(shù)據(jù)長(zhǎng)度發(fā)送到socket緩存區(qū),這樣就可以直接將數(shù)據(jù)從內(nèi)核緩存區(qū)通過(guò)SG-DMA拷貝到網(wǎng)卡,數(shù)據(jù)拷貝到網(wǎng)卡上結(jié)束后再?gòu)膬?nèi)核態(tài)切換到用戶態(tài)。

通過(guò)SG-DMA拷貝就不需要將數(shù)據(jù)拷貝到socket緩存區(qū)再通過(guò)DMA的方式拷貝到網(wǎng)卡了,而是直接從內(nèi)核緩存區(qū)拷貝到網(wǎng)卡。整個(gè)過(guò)程存在了2次用戶態(tài)和內(nèi)核態(tài)的切換,發(fā)生了2次數(shù)據(jù)的拷貝(2次DMA拷貝、0次CPU拷貝)。

 send file + SG-DMA算是真正意義上實(shí)現(xiàn)了零拷貝技術(shù),它整個(gè)過(guò)程都是通過(guò)DMA在系統(tǒng)內(nèi)核完成的,數(shù)據(jù)拷貝不需要CPU參與。

5、splice

在Linux2.6.17內(nèi)核版本中引入了splice系統(tǒng)調(diào)用方法,splice和sendfle方法不同點(diǎn)在于它是不需要硬件支持。如下所示的splice原理圖:

圖片圖片

splice是在內(nèi)核空間的緩存區(qū)和socket緩存區(qū)之間建立管道,從而避免了兩者之間的CPU拷貝操作。splice的整個(gè)拷貝過(guò)程發(fā)生了2次用戶態(tài)和內(nèi)核態(tài)的切換,2次數(shù)據(jù)的拷貝(2次DMA拷貝、0次CPU拷貝)。

總結(jié):

(1)無(wú)論是傳統(tǒng)的IO方式還是零拷貝技術(shù),2次DMA拷貝是必備的(DMA都是依賴硬件完成的),零拷貝只是減少CPU拷貝與上下文的切換(用戶態(tài)和內(nèi)核態(tài)的切換)。

(2)零拷貝的實(shí)現(xiàn)有mmap+write、sendfile、sendfile + SG-DMA、splice等方式。

(3)不是所有的操作系統(tǒng)都支持零拷貝技術(shù),目前只有在使用NIO和 Epoll數(shù)據(jù)傳輸時(shí)才可使用。

(4)RocketMQ和Kafka都使用到了零拷貝的技術(shù)。其中,RocketMQ中生產(chǎn)者發(fā)送數(shù)據(jù)、消費(fèi)者讀取數(shù)據(jù)都是使用mmap+write方式;而Kafka的生產(chǎn)者持久化數(shù)據(jù)使用mmap+write方法,消費(fèi)者讀取數(shù)據(jù)使用sendfile方式。

(5)Java的NIO中MappedByteBuffer底層使用的是mmap;FileChannel的transferTo()/transferFrom(),底層使用sendfile。

責(zé)任編輯:武曉燕 來(lái)源: 龍蝦編程
相關(guān)推薦

2021-12-17 07:47:37

IT風(fēng)險(xiǎn)框架

2022-03-26 09:06:40

ActorCSP模型

2024-05-16 11:13:16

Helm工具release

2009-11-09 12:55:43

WCF事務(wù)

2024-12-18 10:24:59

代理技術(shù)JDK動(dòng)態(tài)代理

2024-12-11 12:00:00

C++拷貝

2022-02-17 09:24:11

TypeScript編程語(yǔ)言javaScrip

2021-04-20 13:59:37

云計(jì)算

2023-12-27 08:15:47

Java虛擬線程

2024-01-16 07:46:14

FutureTask接口用法

2024-08-30 08:50:00

2022-02-24 10:28:23

物聯(lián)網(wǎng)

2013-06-28 14:30:26

棱鏡計(jì)劃棱鏡棱鏡監(jiān)控項(xiàng)目

2020-06-30 10:45:28

Web開(kāi)發(fā)工具

2009-10-29 16:22:10

VB.NET操作MyS

2025-04-01 01:25:00

MySQLInnoDBMyISAM

2017-11-20 10:37:03

2024-08-05 00:04:00

JSWeb應(yīng)用

2024-10-15 09:18:30

2021-02-03 14:31:53

人工智能人臉識(shí)別
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)