關於零拷貝,你應該知道的那些事

最近,學妹在開發一套遠程升級工具,須要將本地的軟件包傳輸到遠程機器上,然而她發現文件傳輸比較慢。因而,我想到了零拷貝技術,遂寫了此文也算對零拷貝作個詳細瞭解。緩存


問題:如今有一個用戶須要讀取磁盤文件上的內容而後將其經過網絡發送出去,假設使用IO系統調用read/write網絡


一、IO原理app

     要了解什麼是零拷貝,首先得知道什麼是IO,以及有哪些類型的IO。通常而言,IO分爲:標準IO庫、IO系統調用、網絡IO庫。socket

IO系統調用ide

     Linux標準訪問文件方式是經過兩個系統調用實現的:read()和write(),這兩個系統調用在用戶態都是沒有緩衝。當用戶進程使用read 和 write 讀寫Linux的文件時,進程會從用戶態進入內核態,經過I/O操做讀取文件中的數據。函數

//read()會把參數fd所指的文件傳送count 個字節到buf 指針所指的內存中。 ssize_t read(int fd, void * buf, size_t count);//write()會把參數buf所指的內存寫入count個字節到參數放到所指的文件內。 ssize_t write (int fd, const void * buf, size_t count);

標準IO庫
工具

       標準IO庫是基於IO系統調用實現的,優化了對系統調用的使用方式。引入標準IO庫主要是對IO系統調用進行封裝。並且,read 和 write 等底層系統調用須要在用戶態和內核態之間切換,若是每次讀寫的數據不多,那麼切換帶來的開銷將大大下降IO的效率,因此標準IO庫在用戶態也引入了緩衝機制,提高了性能。性能

       常見的標準IO庫函數:優化

        fopen、fclose、fwrite、fread、ffulsh、fseek等等。spa

圖片

      假如按照上面IO系統調用方式,要寫入數據到文件上時,內核先將數據寫入到內核中所設的緩衝當中;假如這個緩衝儲存器的長度是100字節,調用系統函數write時,假設每次要寫入的數據的長度爲10個字節,那麼要調用10次write函數才能將內核緩衝區寫滿(內核是由緩衝區的),由此能夠看出,上下文切換的次數是不少的。


      若是按照標準IO庫調用方式,一次調用能夠將數據儘量多的寫入內核緩存,而後由內核態將數據複製到用戶態緩存由於read 和 write 等底層系統調用須要在用戶態內核態之間切換,若是每次讀寫的數據不多,那麼切換帶來的開銷將大大下降IO的效率,因此標準IO庫在用戶態也引入了緩衝機制,提高了性能。採用內核緩存能夠減小磁盤IO的次數,提高磁盤IO的效率。


      如上圖所示,無論採用哪一種方式,從磁盤讀取文件,再到網絡發送。涉及到4次上下文切換和4次拷貝。若是想繼續優化,則須要減小上下文切換次數,也就是要減小系統調用的次數。解決方案就是把 read、write 兩次系統調用合併成一次,在內核中完成磁盤與網卡的數據交換,則提升了性能。

零拷貝

      咱們知道,數據的拷貝是須要藉助內核實現的,而所謂的零拷貝實際上是指在用戶態和內核態沒有了數據拷貝工做。以下圖所示,減小了拷貝次數,也就減小了用戶態和內核態的上下文切換次數。

圖片

    固然了,若是網卡支持 SG-DMA(Direct Memory Access)技術,還能夠再去除 Socket 緩衝區的拷貝,這樣一共只有 2 次內存拷貝。這樣效率會更高,以下圖所示:在用戶態發起一次調用,則內核從磁盤加載數據到內核,而後寫入網卡隊列。寫入成功了,則再內核通知socket結果,而後socket調用返回用戶態。

圖片

       

那麼,咱們再多說兩句。在Linux下,使用sendfile實現零拷貝的調用,其經歷了兩次發展變化。

Linux 2.1內核引入sendfile函數

sendfile經過一次系統調用完成了文件的傳送,經過sendfile發送文件只須要一次系統調用,當調用sendfile時數據的拷貝路徑以下:

第一次拷貝:將數據從磁盤讀取到內核緩衝區中;

第二次拷貝:將數據從內核緩衝區拷貝到socket buffer中;

第三次拷貝:將數據從socket buffer拷貝到網卡設備中發送;

Linux2.4 內核對sendfile作了進一步的改進:

改進後的數據拷貝處理路徑以下:

第一次拷貝:將文件從磁盤拷貝到內核緩衝區中,再也不將內核緩衝區的數據拷貝到socket buffer,而是向socket buffer中寫入當前要發送的數據在內核緩衝區中的位置和偏移量;

第二次拷貝:根據socket buffer中的位置和偏移量,直接將內核緩衝區的數據copy到網卡設備中;

總結:

       每次IO請求,內核態和用戶態的切換開銷以及數據的拷貝開銷會嚴重下降性能,因此零拷貝技術能夠來省掉用戶態和內核態之間多餘的數據拷貝,大大提升了應用程序的性能,而且減小了內核態和用戶態的上下文的切換。對於零拷貝須要記住如下2點:

  1. 零拷貝能夠將讀取磁盤文件網絡傳輸的上下文切換的次數從4次下降到2次;數據拷貝次數從4次下降到2次;

  2. 零拷貝是針對內核來講,數據在內核模式下是無拷貝的,並非指整個過程數據沒有拷貝;

相關文章
相關標籤/搜索