零拷貝Zero-copy技術(shù)詳解

普通模式數(shù)據(jù)交互

普通模式數(shù)據(jù)交互分為僅CPU和CPU&DMA兩種方式潮罪。

僅CPU方式

read流程:

  1. 當(dāng)程序執(zhí)行read()時(shí)匆绣,調(diào)用syscall從用戶態(tài)切換到內(nèi)核態(tài)节腐;
  2. CPU向磁盤(pán)發(fā)起IO請(qǐng)求燕差,磁盤(pán)收到后開(kāi)始Ready數(shù)據(jù)捂襟;
  3. 磁盤(pán)將數(shù)據(jù)放到磁盤(pán)緩沖區(qū)之后絮爷,向CPU發(fā)起I/O中斷趴酣,報(bào)告CPU數(shù)據(jù)已經(jīng)Ready了(可見(jiàn)其使用了 Page Cache 機(jī)制);
  4. CPU收到磁盤(pán)控制器的I/O中斷之后坑夯,把磁盤(pán)緩沖區(qū)數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)中岖寞;
  5. 然后再把數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū)中
  6. 完成之后syscall返回,也就是read()的返回柜蜈,從內(nèi)核態(tài)切換到用戶態(tài)仗谆;
CPU.png

小結(jié):

  • 僅CPU方式read流程經(jīng)歷了2次CPU拷貝,2次空間切換淑履。
  • 而write流程也是2次CPU拷貝隶垮,2次空間切換。

CPU&DMA

我們可以看出僅CPU方式需要跟硬件交互秘噪,很耗CPU狸吞,這是在浪費(fèi)CPU資源。
于是就有了DMA(Direct Memory Access缆娃, 直接內(nèi)存訪問(wèn))來(lái)分擔(dān)CPU的活捷绒。

有必要先講一下DMA是什么,DMA是一種硬件設(shè)備繞開(kāi)CPU獨(dú)立直接訪問(wèn)內(nèi)存的機(jī)制贯要。所以DMA在一定程度上解放了CPU暖侨,與硬件交互的工作讓硬件直接自己做了,提高了CPU效率崇渗。支持DMA的有網(wǎng)卡字逗、聲卡京郑、顯卡、磁盤(pán)控制器等葫掉。

CPU&DMA方式對(duì)比僅CPU方式的區(qū)別就是些举,CPU不再和磁盤(pán)直接交互,而是DMA和磁盤(pán)交互俭厚,使得讀寫(xiě)運(yùn)行效率更高户魏。
并且在DMA讀寫(xiě)硬件時(shí),CPU可以執(zhí)行其他任務(wù)挪挤。

read流程:

  1. 當(dāng)程序執(zhí)行read()時(shí)叼丑,調(diào)用syscall從用戶態(tài)切換到內(nèi)核態(tài);
  2. DMA向磁盤(pán)發(fā)起IO請(qǐng)求扛门,磁盤(pán)收到后開(kāi)始Ready數(shù)據(jù)鸠信;
  3. 磁盤(pán)將數(shù)據(jù)放到磁盤(pán)緩沖區(qū)之后,向DMA發(fā)起信號(hào)论寨,報(bào)告DMA數(shù)據(jù)已經(jīng)Ready了星立;
  4. DMA收到磁盤(pán)控制器的I/O中斷之后,把磁盤(pán)緩沖區(qū)數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)中葬凳;
  5. 然后CPU再把數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū)中绰垂;
  6. 完成之后syscall返回,也就是read()的返回沮明,從內(nèi)核態(tài)切換到用戶態(tài)辕坝。
CPU&DMA.png

小結(jié):

  • CPU&DMA方式read流程經(jīng)歷了1次CPU拷貝,1次DMA拷貝荐健,2次空間切換酱畅。
  • 而write流程也是1次CPU拷貝,1次DMA拷貝江场,2次空間切換纺酸。

Zero-Copy技術(shù)

通過(guò)上面兩種普通模式數(shù)據(jù)交互的方式發(fā)現(xiàn),如果我們執(zhí)行read和write操作址否,會(huì)經(jīng)歷四次數(shù)據(jù)拷貝和四次空間切換餐蔬。基于這兩點(diǎn)我們可以做如下優(yōu)化:

  • 內(nèi)核緩沖區(qū)->用戶緩沖區(qū)->套接字緩沖區(qū)這兩次數(shù)據(jù)拷貝是有冗余的佑附,我們可以優(yōu)化成從內(nèi)核緩沖區(qū)直接拷貝到套接字緩沖區(qū)樊诺;
  • 四次空間切換是比較耗時(shí)的操作,我們可以減少空間切換次數(shù)來(lái)增加效率音同。

當(dāng)程序中有系統(tǒng)調(diào)用語(yǔ)句词爬,程序執(zhí)行到系統(tǒng)調(diào)用時(shí),首先使用類似int 80H的軟中斷指令权均,保存現(xiàn)場(chǎng)顿膨,去系統(tǒng)調(diào)用锅锨,在內(nèi)核態(tài)執(zhí)行,然后恢復(fù)現(xiàn)場(chǎng)恋沃。每個(gè)進(jìn)程都會(huì)有兩個(gè)棧必搞,一個(gè)內(nèi)核態(tài)棧和一個(gè)用戶態(tài)棧。當(dāng)int中斷執(zhí)行時(shí)就會(huì)由用戶態(tài)棧轉(zhuǎn)向內(nèi)核態(tài)棧囊咏,系統(tǒng)調(diào)用時(shí)需要進(jìn)行棧的切換恕洲。而且內(nèi)核代碼對(duì)用戶不信任,需要進(jìn)行額外的檢查匆笤。系統(tǒng)調(diào)用的返回過(guò)程有很多額外工作研侣,比如檢查是否需要調(diào)度等。

系統(tǒng)調(diào)用一般都需要保存用戶程序得上下文(context)炮捧,在進(jìn)入內(nèi)核的時(shí)候需要保存用戶態(tài)的寄存器,在內(nèi)核態(tài)返回用戶態(tài)的時(shí)候會(huì)恢復(fù)這些寄存器的內(nèi)容惦银。這是一個(gè)開(kāi)銷(xiāo)的地方咆课。 如果需要在不同用戶程序間切換的話,還要更新cr3寄存器扯俱,這樣會(huì)更換每個(gè)程序的虛擬內(nèi)存到物理內(nèi)存映射表的地址书蚪,也是一個(gè)比較高負(fù)擔(dān)的操作

基于上面兩點(diǎn)優(yōu)化,實(shí)現(xiàn)了這些零拷貝技術(shù):mmap+write迅栅、sendfile殊校、sendfile+DMA收集、splice等读存。

mmap+write

mmap即memory map为流,也就是內(nèi)存映射。我在mmap的使用一文中詳細(xì)介紹了mmap的用法让簿、特點(diǎn)敬察、注意事項(xiàng)等信息,感興趣的同學(xué)可以去看看尔当。

mmap+write流程:

  1. 用戶進(jìn)程調(diào)用 mmap()莲祸,從用戶態(tài)切換到內(nèi)核態(tài),將內(nèi)核緩沖區(qū)映射到用戶緩存區(qū)椭迎;
  2. DMA 控制器將數(shù)據(jù)從硬盤(pán)拷貝到內(nèi)核緩沖區(qū)锐帜;
  3. mmap() 返回,上下文從內(nèi)核態(tài)切換回用戶態(tài)畜号;
  4. 用戶進(jìn)程調(diào)用 write()缴阎,從用戶態(tài)切換到內(nèi)核態(tài);
  5. CPU 將內(nèi)核緩沖區(qū)中的數(shù)據(jù)拷貝到的套接字緩沖區(qū)弄兜;
  6. DMA 控制器將數(shù)據(jù)從套接字緩沖區(qū)拷貝到網(wǎng)卡完成數(shù)據(jù)傳輸药蜻;
  7. write() 返回瓷式,從內(nèi)核態(tài)切換回用戶態(tài)。
MMap.png

小結(jié):

  • MMap+write流程經(jīng)歷了1次CPU拷貝语泽,2次DMA拷貝贸典,4次空間切換。比CPU&DMA少了一次CPU拷貝踱卵。

sendfile

不管是ready+write還是mmap+write廊驼,都是使用兩個(gè)接口來(lái)做數(shù)據(jù)傳輸,按照第二點(diǎn)優(yōu)化思路惋砂,我們可以用一個(gè)系統(tǒng)調(diào)用接口來(lái)實(shí)現(xiàn)妒挎,這樣空間切換就會(huì)從四次縮為兩次。
sendfile是Linux 內(nèi)核2.1版本中被引入西饵,與mmap+write一樣酝掩,sendfile是從內(nèi)核緩沖區(qū)拷貝到socket緩沖區(qū),流程如下:

Sendfile.png

小結(jié):

  • sendfile流程經(jīng)歷了1次CPU拷貝眷柔,2次DMA拷貝期虾,2次空間切換。比CPU&DMA少了一次CPU拷貝和兩次空間切換驯嘱,由于數(shù)據(jù)不經(jīng)過(guò)用戶緩沖區(qū)镶苞,因此數(shù)據(jù)無(wú)法被修改。

sendfile+DMA

從 Linux 內(nèi)核 2.4 版本開(kāi)始起鞠评,sendfile() 系統(tǒng)調(diào)用的過(guò)程發(fā)生了點(diǎn)變化茂蚓,具體過(guò)程如下:

  • 通過(guò) DMA 將磁盤(pán)上的數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)里;
  • 將內(nèi)核空間緩沖區(qū)中對(duì)應(yīng)的數(shù)據(jù)描述信息(文件描述符剃幌、地址偏移量等信息)記錄到socket緩沖區(qū)中聋涨。
  • DMA控制器根據(jù)socket緩沖區(qū)中的地址和偏移量將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到網(wǎng)卡中,從而省去了內(nèi)核空間中僅剩1次CPU拷貝锥忿。

這種方式才是實(shí)現(xiàn)了真正的零拷貝牛郑,真正的解放了CPU。但是這種方式需要硬件DMA控制器的配合敬鬓。流程圖示如下:


sendfile+dma.png

小結(jié):

  • sendfile+DMA流程經(jīng)歷了0次CPU拷貝淹朋,2次DMA拷貝,2次空間切換钉答。比CPU&DMA少了兩次CPU拷貝和兩次空間切換础芍,需要DMA支持,數(shù)據(jù)仍然無(wú)法被修改数尿。

splice

  • splice系統(tǒng)調(diào)用是Linux 在 2.6 版本引入的仑性,其不需要硬件支持,并且不再限定于socket上右蹦,實(shí)現(xiàn)兩個(gè)普通文件之間的數(shù)據(jù)零拷貝诊杆。
  • splice 系統(tǒng)調(diào)用可以在內(nèi)核緩沖區(qū)和socket緩沖區(qū)之間建立管道來(lái)傳輸數(shù)據(jù)歼捐,避免了兩者之間的 CPU 拷貝操作。
  • splice也有一些局限晨汹,它的兩個(gè)文件描述符參數(shù)中有一個(gè)必須是管道設(shè)備豹储。
splice.png

小結(jié):

  • splice流程經(jīng)歷了0次CPU拷貝,2次DMA拷貝淘这,2次空間切換剥扣。比CPU&DMA少了兩次CPU拷貝和兩次空間切換,數(shù)據(jù)仍然無(wú)法被修改铝穷,但是不依賴硬件钠怯,只要有一個(gè)管道設(shè)備即可。

大文件傳輸

內(nèi)核緩沖區(qū)

為什么磁盤(pán)數(shù)據(jù)拷貝到網(wǎng)卡中曙聂,需要經(jīng)過(guò)內(nèi)核緩沖區(qū)呢晦炊?原因是磁盤(pán)的讀寫(xiě)速度太慢。
內(nèi)核緩沖區(qū)工作:

  • 緩存最近被訪問(wèn)的數(shù)據(jù)宁脊。最近訪問(wèn)過(guò)的數(shù)據(jù)接下來(lái)很可能還會(huì)被訪問(wèn)刽锤,所以利用PageCache 緩存最近被訪問(wèn)的數(shù)據(jù),讀磁盤(pán)數(shù)據(jù)的時(shí)候朦佩,優(yōu)先在 PageCache 找,如果數(shù)據(jù)存在則可以直接返回庐氮;如果沒(méi)有语稠,則從磁盤(pán)中讀取,然后緩存在 PageCache 中弄砍。當(dāng)PageCache的空間不足時(shí)仙畦,淘汰最久未被訪問(wèn)的緩存。
  • 預(yù)讀功能音婶。利用空間局部性原理慨畸,假設(shè) read 方法每次只會(huì)讀 32 KB 的字節(jié),雖然 read 剛開(kāi)始只會(huì)讀 0 ~ 32 KB 的字節(jié)衣式,但內(nèi)核會(huì)把其后面的 32~64 KB 也讀取到 PageCache寸士,這樣后面讀取 32~64 KB 的成本就很低,如果在 32~64 KB 淘汰出 PageCache 前碴卧,進(jìn)程讀取到它了弱卡,收益就非常大。
  • 內(nèi)核的 I/O 調(diào)度算法會(huì)緩存盡可能多的 I/O 請(qǐng)求在 內(nèi)核緩存區(qū)中住册,最后合并成一個(gè)更大的 I/O 請(qǐng)求再發(fā)給磁盤(pán)婶博,這樣做是為了減少磁盤(pán)的尋址操作。

大文件的緩存命中率不高荧飞,并且可能內(nèi)核緩存區(qū)被大文件占據(jù)凡人,而導(dǎo)致其他的熱點(diǎn)小文件無(wú)法利用內(nèi)核緩存區(qū)名党。
所以適用內(nèi)核緩沖器時(shí),不適合大文件傳輸挠轴。也就是說(shuō)零拷貝技術(shù)不適合大文件傳輸传睹。

異步IO

我們了解了為什么使用內(nèi)核緩沖區(qū)后,就能自然而然的想到忠荞,如果可以忍受磁盤(pán)讀寫(xiě)速度就可以避免使用內(nèi)核緩沖區(qū)蒋歌。
異步IO就是可以忍受磁盤(pán)讀寫(xiě)速度,因?yàn)榫€程不用等待異步IO的執(zhí)行結(jié)果委煤。
所以異步IO可以做到直接從磁盤(pán)緩沖區(qū)拷貝到用戶緩沖區(qū)堂油,適用于大文件傳輸。

總結(jié)

本文介紹了CPU和CPU&DMA兩種數(shù)據(jù)傳輸?shù)牧鞒蹋?/p>

  • 僅CPU方式的read+write流程經(jīng)歷了4次CPU拷貝碧绞,4次空間切換
  • CPU&DMA方式的read+write流程經(jīng)歷了2次CPU拷貝府框,2次DMA拷貝,4次空間切換讥邻。

然后介紹了優(yōu)化的點(diǎn)分別是減少數(shù)據(jù)拷貝次數(shù)和介紹空間切換次數(shù)迫靖,于是引出了零拷貝技術(shù):mmap+write、sendfile兴使、sendfile+DMA收集系宜、splice等。

  • MMap+write流程經(jīng)歷了1次CPU拷貝发魄,2次DMA拷貝盹牧,4次空間切換。比CPU&DMA少了一次CPU拷貝励幼。
  • sendfile流程經(jīng)歷了1次CPU拷貝汰寓,2次DMA拷貝,2次空間切換苹粟。比CPU&DMA少了一次CPU拷貝和兩次空間切換有滑,由于數(shù)據(jù)不經(jīng)過(guò)用戶緩沖區(qū),因此數(shù)據(jù)無(wú)法被修改嵌削。
  • sendfile+DMA流程經(jīng)歷了0次CPU拷貝毛好,2次DMA拷貝,2次空間切換掷贾。比CPU&DMA少了兩次CPU拷貝和兩次空間切換睛榄,需要DMA支持,數(shù)據(jù)仍然無(wú)法被修改想帅。
  • splice流程經(jīng)歷了0次CPU拷貝场靴,2次DMA拷貝,2次空間切換。比CPU&DMA少了兩次CPU拷貝和兩次空間切換旨剥,數(shù)據(jù)仍然無(wú)法被修改咧欣,但是不依賴硬件,只要有一個(gè)管道設(shè)備即可轨帜。

最后介紹了內(nèi)核緩沖區(qū)的作用魄咕,也引出了異步IO可以處理大文件傳輸工作。

引用

wiki Page_cache
wiki Zero-copy
wiki Mmap
man2 sendfile
wiki Splice

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚌父,一起剝皮案震驚了整個(gè)濱河市哮兰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苟弛,老刑警劉巖喝滞,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異膏秫,居然都是意外死亡右遭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)缤削,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)窘哈,“玉大人,你說(shuō)我怎么就攤上這事亭敢」鐾瘢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵帅刀,是天一觀的道長(zhǎng)满哪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)劝篷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任民宿,我火速辦了婚禮娇妓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘活鹰。我一直安慰自己哈恰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布志群。 她就那樣靜靜地躺著着绷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锌云。 梳的紋絲不亂的頭發(fā)上荠医,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼彬向。 笑死兼贡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的娃胆。 我是一名探鬼主播遍希,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼里烦!你這毒婦竟也來(lái)了凿蒜?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胁黑,失蹤者是張志新(化名)和其女友劉穎废封,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體别厘,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虱饿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了触趴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氮发。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖冗懦,靈堂內(nèi)的尸體忽然破棺而出爽冕,到底是詐尸還是另有隱情,我是刑警寧澤披蕉,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布颈畸,位于F島的核電站,受9級(jí)特大地震影響没讲,放射性物質(zhì)發(fā)生泄漏眯娱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一爬凑、第九天 我趴在偏房一處隱蔽的房頂上張望徙缴。 院中可真熱鬧,春花似錦嘁信、人聲如沸于样。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)穿剖。三九已至,卻和暖如春卦溢,著一層夾襖步出監(jiān)牢的瞬間糊余,已是汗流浹背秀又。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啄刹,地道東北人涮坐。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像誓军,于是被迫代替她去往敵國(guó)和親袱讹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容