Linux零拷貝原理

大白話解釋蹦骑,零拷貝就是沒有把數(shù)據(jù)從一個(gè)存儲區(qū)域拷貝到另一個(gè)存儲區(qū)域曼库。但是沒有數(shù)據(jù)的復(fù)制区岗,怎么可能實(shí)現(xiàn)數(shù)據(jù)的傳輸呢?其實(shí)我們在java NIO毁枯、netty慈缔、kafka遇到的零拷貝,并不是不復(fù)制數(shù)據(jù)种玛,而是減少不必要的數(shù)據(jù)拷貝次數(shù)藐鹤,從而提升代碼性能

零拷貝的好處

內(nèi)核空間和用戶空間

緩沖區(qū)和虛擬內(nèi)存

傳統(tǒng)的 I/O

mmap+write 實(shí)現(xiàn)的零拷貝

sendfile 實(shí)現(xiàn)的零拷貝

帶有DMA收集拷貝功能的sendfile實(shí)現(xiàn)的零拷貝

java提供的零拷貝方式

零拷貝的好處

減少或避免不必要的CPU數(shù)據(jù)拷貝,從而釋放CPU去執(zhí)行其他任務(wù)

零拷貝機(jī)制能減少用戶空間和操作系統(tǒng)內(nèi)核空間的上下文切換

減少內(nèi)存的占用

內(nèi)核空間和用戶空間

內(nèi)核空間:Linux自身使用的空間赂韵;主要提供進(jìn)程調(diào)度娱节、內(nèi)存分配、連接硬件資源等功能

用戶空間:提供給各個(gè)程序進(jìn)程的空間祭示;用戶空間不具有訪問內(nèi)核空間資源的權(quán)限肄满,如果應(yīng)用程序需要使用到內(nèi)核空間的資源,則需要通過系統(tǒng)調(diào)用來完成:從用戶空間切換到內(nèi)核空間质涛,完成相關(guān)操作后再從內(nèi)核空間切換回用戶空間

緩沖區(qū)和虛擬內(nèi)存

直接內(nèi)存訪問(Direct Memory Access)(DMA)

直接內(nèi)存訪問:DMA允許外設(shè)設(shè)備和內(nèi)存存儲器之間直接進(jìn)行IO數(shù)據(jù)傳輸稠歉,其過程不需要CPU的參與

緩沖區(qū) 是所有I/O的基礎(chǔ),I/O 無非就是把數(shù)據(jù)移進(jìn)或移出緩沖區(qū)

進(jìn)程發(fā)起read請求汇陆,內(nèi)核先檢查內(nèi)核空間緩沖區(qū)是否存在進(jìn)程所需數(shù)據(jù)怒炸,如果已經(jīng)存在,則直接copy數(shù)據(jù)到進(jìn)程的內(nèi)存區(qū)毡代。如果沒有阅羹,系統(tǒng)則向磁盤請求數(shù)據(jù)勺疼,通過DMA寫入內(nèi)核的read緩沖沖區(qū),接著再將內(nèi)核緩沖區(qū)數(shù)據(jù)copy到進(jìn)程的內(nèi)存區(qū)

進(jìn)程發(fā)起write請求捏鱼,則是把進(jìn)程的內(nèi)存區(qū)數(shù)據(jù)copy到內(nèi)核的write緩沖區(qū)恢口,然后再通過DMA把內(nèi)核緩沖區(qū)數(shù)據(jù)刷回磁盤或者網(wǎng)卡中

虛擬內(nèi)存:現(xiàn)代操作系統(tǒng)都使用虛擬內(nèi)存,有如下兩個(gè)好處

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

虛擬內(nèi)存空間可大于實(shí)際可用的物理地址

利用第一點(diǎn)特性可以把內(nèi)核空間地址和用戶空間的虛擬地址映射到同一個(gè)物理地址穷躁,這樣DMA就可以填充(讀寫)對內(nèi)核和用戶空間進(jìn)程同時(shí)可見的緩沖區(qū)了;大致如下

傳統(tǒng)的 I/O

#include<unistd>ssize_twrite(intfiledes,void*buf,size_tnbytes);ssize_tread(intfiledes,void*buf,size_tnbytes);

如java在linux系統(tǒng)上因妇,讀取一個(gè)磁盤文件问潭,并發(fā)送到遠(yuǎn)程端的服務(wù)

1)發(fā)出read系統(tǒng)調(diào)用,會導(dǎo)致用戶空間到內(nèi)核空間的上下文切換婚被,然后再通過DMA將文件中的數(shù)據(jù)從磁盤上讀取到內(nèi)核空間緩沖區(qū)

2)接著將內(nèi)核空間緩沖區(qū)的數(shù)據(jù)拷貝到用戶空間進(jìn)程內(nèi)存狡忙,然后read系統(tǒng)調(diào)用返回。而系統(tǒng)調(diào)用的返回又會導(dǎo)致一次內(nèi)核空間到用戶空間的上下文切換

3)write系統(tǒng)調(diào)用址芯,則再次導(dǎo)致用戶空間到內(nèi)核空間的上下文切換灾茁,將用戶空間的進(jìn)程里的內(nèi)存數(shù)據(jù)復(fù)制到內(nèi)核空間的socket緩沖區(qū)(也是內(nèi)核緩沖區(qū),不過是給socket使用的)谷炸,然后write系統(tǒng)調(diào)用返回北专,再次觸發(fā)上下文切換

4)至于socket緩沖區(qū)到網(wǎng)卡的數(shù)據(jù)傳輸則是獨(dú)立異步的過程,也就是說write系統(tǒng)調(diào)用的返回并不保證數(shù)據(jù)被傳輸?shù)骄W(wǎng)卡

「一共有四次用戶空間與內(nèi)核空間的上下文切換旬陡。四次數(shù)據(jù)copy拓颓,分別是兩次CPU數(shù)據(jù)復(fù)制,兩次DMA數(shù)據(jù)復(fù)制」

mmap+write實(shí)現(xiàn)的零拷貝

#include<sys/mman.h>void*mmap(void*start,size_tlength,intprot,intflags,intfd,off_toffset)

1)發(fā)出mmap系統(tǒng)調(diào)用描孟,導(dǎo)致用戶空間到內(nèi)核空間的上下文切換驶睦。然后通過DMA引擎將磁盤文件中的數(shù)據(jù)復(fù)制到內(nèi)核空間緩沖區(qū)

2)mmap系統(tǒng)調(diào)用返回,導(dǎo)致內(nèi)核空間到用戶空間的上下文切換

3)這里不需要將數(shù)據(jù)從內(nèi)核空間復(fù)制到用戶空間匿醒,因?yàn)橛脩艨臻g和內(nèi)核空間共享了這個(gè)緩沖區(qū)

4)發(fā)出write系統(tǒng)調(diào)用场航,導(dǎo)致用戶空間到內(nèi)核空間的上下文切換。將數(shù)據(jù)從內(nèi)核空間緩沖區(qū)復(fù)制到內(nèi)核空間socket緩沖區(qū)廉羔;write系統(tǒng)調(diào)用返回溉痢,導(dǎo)致內(nèi)核空間到用戶空間的上下文切換

5)異步,DMA引擎將socket緩沖區(qū)中的數(shù)據(jù)copy到網(wǎng)卡

「通過mmap實(shí)現(xiàn)的零拷貝I/O進(jìn)行了4次用戶空間與內(nèi)核空間的上下文切換蜜另,以及3次數(shù)據(jù)拷貝适室;其中3次數(shù)據(jù)拷貝中包括了2次DMA拷貝和1次CPU拷貝」

sendfile實(shí)現(xiàn)的零拷貝

#include <sys/sendfile.h>

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

1)發(fā)出sendfile系統(tǒng)調(diào)用,導(dǎo)致用戶空間到內(nèi)核空間的上下文切換举瑰,然后通過DMA引擎將磁盤文件中的內(nèi)容復(fù)制到內(nèi)核空間緩沖區(qū)中捣辆,接著再將數(shù)據(jù)從內(nèi)核空間緩沖區(qū)復(fù)制到socket相關(guān)的緩沖區(qū)

2)sendfile系統(tǒng)調(diào)用返回,導(dǎo)致內(nèi)核空間到用戶空間的上下文切換此迅。DMA異步將內(nèi)核空間socket緩沖區(qū)中的數(shù)據(jù)傳遞到網(wǎng)卡

「通過sendfile實(shí)現(xiàn)的零拷貝I/O使用了2次用戶空間與內(nèi)核空間的上下文切換汽畴,以及3次數(shù)據(jù)的拷貝旧巾。其中3次數(shù)據(jù)拷貝中包括了2次DMA拷貝和1次CPU拷貝」

帶有DMA收集拷貝功能的sendfile實(shí)現(xiàn)的零拷貝

從Linux 2.4版本開始,操作系統(tǒng)提供scatter和gather的SG-DMA方式忍些,直接從內(nèi)核空間緩沖區(qū)中將數(shù)據(jù)讀取到網(wǎng)卡鲁猩,無需將內(nèi)核空間緩沖區(qū)的數(shù)據(jù)再復(fù)制一份到socket緩沖區(qū)

1)發(fā)出sendfile系統(tǒng)調(diào)用,導(dǎo)致用戶空間到內(nèi)核空間的上下文切換罢坝。通過DMA引擎將磁盤文件中的內(nèi)容復(fù)制到內(nèi)核空間緩沖區(qū)

2)這里沒把數(shù)據(jù)復(fù)制到socket緩沖區(qū)廓握;取而代之的是,相應(yīng)的描述符信息被復(fù)制到socket緩沖區(qū)嘁酿。該描述符包含了兩種的信息:A)內(nèi)核緩沖區(qū)的內(nèi)存地址隙券、B)內(nèi)核緩沖區(qū)的偏移量

3)sendfile系統(tǒng)調(diào)用返回,導(dǎo)致內(nèi)核空間到用戶空間的上下文切換闹司。DMA根據(jù)socket緩沖區(qū)的描述符提供的地址和偏移量直接將內(nèi)核緩沖區(qū)中的數(shù)據(jù)復(fù)制到網(wǎng)卡

「帶有DMA收集拷貝功能的sendfile實(shí)現(xiàn)的I/O使用了2次用戶空間與內(nèi)核空間的上下文切換娱仔,以及2次數(shù)據(jù)的拷貝,而且這2次的數(shù)據(jù)拷貝都是非CPU拷貝游桩。這樣一來我們就實(shí)現(xiàn)了最理想的零拷貝I/O傳輸了牲迫,不需要任何一次的CPU拷貝,以及最少的上下文切換」

java提供的零拷貝方式

java NIO的零拷貝實(shí)現(xiàn)是基于mmap+write方式

FileChannel的map方法產(chǎn)生的MappedByteBuffer FileChannel提供了map()方法借卧,該方法可以在一個(gè)打開的文件和MappedByteBuffer之間建立一個(gè)虛擬內(nèi)存映射盹憎,MappedByteBuffer繼承于ByteBuffer;該緩沖器的內(nèi)存是一個(gè)文件的內(nèi)存映射區(qū)域谓娃。map方法底層是通過mmap實(shí)現(xiàn)的脚乡,因此將文件內(nèi)存從磁盤讀取到內(nèi)核緩沖區(qū)后,用戶空間和內(nèi)核空間共享該緩沖區(qū)滨达。用法如下

FileChannel的transferTo奶稠、transferFrom 如果操作系統(tǒng)底層支持的話,transferTo捡遍、transferFrom也會使用相關(guān)的零拷貝技術(shù)來實(shí)現(xiàn)數(shù)據(jù)的傳輸锌订。用法如下

作者:cscw

來源:掘金

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市画株,隨后出現(xiàn)的幾起案子辆飘,更是在濱河造成了極大的恐慌,老刑警劉巖谓传,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜈项,死亡現(xiàn)場離奇詭異,居然都是意外死亡续挟,警方通過查閱死者的電腦和手機(jī)紧卒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诗祸,“玉大人跑芳,你說我怎么就攤上這事轴总。” “怎么了博个?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵怀樟,是天一觀的道長。 經(jīng)常有香客問我盆佣,道長往堡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任共耍,我火速辦了婚禮投蝉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘征堪。我一直安慰自己,他們只是感情好关拒,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布佃蚜。 她就那樣靜靜地躺著,像睡著了一般着绊。 火紅的嫁衣襯著肌膚如雪谐算。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天归露,我揣著相機(jī)與錄音洲脂,去河邊找鬼。 笑死剧包,一個(gè)胖子當(dāng)著我的面吹牛恐锦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疆液,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼一铅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了堕油?” 一聲冷哼從身側(cè)響起潘飘,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掉缺,沒想到半個(gè)月后卜录,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡眶明,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年艰毒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赘来。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡现喳,死狀恐怖凯傲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嗦篱,我是刑警寧澤冰单,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站灸促,受9級特大地震影響诫欠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浴栽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一荒叼、第九天 我趴在偏房一處隱蔽的房頂上張望梧宫。 院中可真熱鬧瘦棋,春花似錦、人聲如沸谅海。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至球碉,卻和暖如春蜓斧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背睁冬。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工挎春, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人豆拨。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓直奋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親施禾。 傳聞我的和親對象是個(gè)殘疾皇子帮碰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361